update_fields example python django django-signals

python - update_fields - django signals example



Django post_save evita la recursiĆ³n sin anular el modelo guardar() (8)

¿Qué piensas de esta solución?

@receiver(post_save, sender=Article) def generate_thumbnails(sender, instance=None, created=False, **kwargs): if not instance: return if hasattr(instance, ''_dirty''): return do_something() try: instance._dirty = True instance.save() finally: del instance._dirty

También puedes crear decorador.

def prevent_recursion(func): @wraps(func) def no_recursion(sender, instance=None, **kwargs): if not instance: return if hasattr(instance, ''_dirty''): return func(sender, instance=instance, **kwargs) try: instance._dirty = True instance.save() finally: del instance._dirty return no_recursion @receiver(post_save, sender=Article) @prevent_recursion def generate_thumbnails(sender, instance=None, created=False, **kwargs): do_something()

Hay muchas publicaciones de Desbordamiento de pila sobre la recursión utilizando la señal de post_save , a las que los comentarios y las respuestas son abrumadoramente: "¿por qué no anular el guardado ()" o un guardado que solo se activa cuando se created == True .

Bueno, creo que hay un buen caso para no usar save() ; por ejemplo, estoy agregando una aplicación temporal que maneja los datos de cumplimiento de pedidos completamente separados de nuestro modelo de pedidos.

El resto del marco es felizmente inconsciente de la aplicación de cumplimiento y el uso de ganchos post_save aísla todo el código relacionado con el cumplimiento de nuestro modelo de pedido.

Si abandonamos el servicio de cumplimiento, nada de nuestro código central tiene que cambiar. Eliminamos la aplicación de cumplimiento, y eso es todo.

Entonces, ¿hay algún método decente para garantizar que la señal post_save no active el mismo controlador dos veces?


¿Qué tal desconectar y luego volver a conectar la señal dentro de su función post_save ?

def my_post_save_handler(sender, instance, **kwargs): post_save.disconnect(my_post_save_handler, sender=sender) instance.do_stuff() instance.save() post_save.connect(my_post_save_handler, sender=sender) post_save.connect(my_post_save_handler, sender=Order)


Creo que crear un método save_without_signals() en el modelo es más explícito:

class MyModel() def __init__(): # Call super here. self._disable_signals = False def save_without_signals(self): """ This allows for updating the model from code running inside post_save() signals without going into an infinite loop: """ self._disable_signals = True self.save() self._disable_signals = False def my_model_post_save(sender, instance, *args, **kwargs): if not instance._disable_signals: # Execute the code here.


Deberías usar queryset.update () en lugar de Model.save () pero necesitas ocuparte de otra cosa:

Es importante tener en cuenta que cuando lo use, si desea usar el nuevo objeto, debe volver a obtenerlo, porque no cambiará el objeto propio, por ejemplo:

>>> MyModel.objects.create(pk=1, text='''') >>> el = MyModel.objects.get(pk=1) >>> queryset.filter(pk=1).update(text=''Updated'') >>> print el.text >>> ''''

Entonces, si quieres usar el nuevo objeto debes hacerlo de nuevo:

>>> MyModel.objects.create(pk=1, text='''') >>> el = MyModel.objects.get(pk=1) >>> queryset.filter(pk=1).update(text=''Updated'') >>> el = MyModel.objects.get(pk=1) # Do it again >>> print el.text >>> ''Updated''


Mira esto...

Cada señal tiene sus propios beneficios, como puede leer en los documentos aquí, pero quería compartir un par de cosas para tener en cuenta con las señales pre_save y post_save.

  • Ambos se llaman cada vez que se llama .save () en un modelo. En otras palabras, si guarda la instancia del modelo, las señales se envían.

  • ejecutar save () en la instancia dentro de post_save a menudo puede crear un bucle interminable y, por lo tanto, puede causar un error de superación de la profundidad máxima de recursión --- solo si no usa .save () correctamente.

  • pre_save es ideal para cambiar solo datos de instancia porque no tiene que llamar a save () nunca, lo que elimina la posibilidad de lo anterior. La razón por la que no tiene que llamar a save () es porque una señal de pre_save significa literalmente justo antes de ser guardada.

  • Las señales pueden llamar a otras señales o ejecutar tareas demoradas (para apio) que pueden ser enormes para la facilidad de uso.

Fuente: https://www.codingforentrepreneurs.com/blog/post-save-vs-pre-save-vs-override-save-method/

¡¡Saludos!!


No desconecte las señales. Si se genera un nuevo modelo del mismo tipo mientras la señal se desconecta, la función del controlador no se activará. Las señales son globales en Django y varias solicitudes pueden ejecutarse al mismo tiempo, lo que hace que algunas fallen mientras que otras ejecutan su controlador post_save.


Puede utilizar la actualización en lugar de guardar en el controlador de señal.

quersyset.filter(pk=instance.pk).update(....)


También puede verificar el argumento en raw en post_save y luego llamar a save_base lugar de save .