Señales de Django frente al método de guardado anulado

89

Estoy teniendo problemas para entender esto. Ahora mismo tengo algunos modelos que se parecen a esto:

 def Review(models.Model)
    ...fields...
    overall_score = models.FloatField(blank=True)

def Score(models.Model)
    review = models.ForeignKey(Review)
    question = models.TextField()
    grade = models.IntegerField()

Una revisión tiene varias "puntuaciones", la puntuación global es el promedio de las puntuaciones. Cuando se guarda una reseña o una puntuación, necesito volver a calcular el promedio de puntuación general. Ahora mismo estoy usando un método de guardado anulado. ¿Habría algún beneficio al usar el despachador de señales de Django?

imjoevasquez
fuente

Respuestas:

84

Las señales de guardar / eliminar son generalmente favorables en situaciones en las que necesita realizar cambios que no son completamente específicos del modelo en cuestión, o podrían aplicarse a modelos que tienen algo en común, o podrían configurarse para su uso entre modelos.

Una tarea común en los savemétodos anulados es la generación automática de slugs a partir de algún campo de texto en un modelo. Ese es un ejemplo de algo que, si necesita implementarlo para varios modelos, se beneficiaría del uso de una pre_saveseñal, donde el manejador de señales podría tomar el nombre del campo slug y el nombre del campo desde el que generar el slug. Una vez que tenga algo así en su lugar, cualquier funcionalidad mejorada que implemente también se aplicará a todos los modelos, por ejemplo, buscar la barra que está a punto de agregar para el tipo de modelo en cuestión, para garantizar la singularidad.

Las aplicaciones reutilizables a menudo se benefician del uso de señales: si la funcionalidad que proporcionan se puede aplicar a cualquier modelo, generalmente (a menos que sea inevitable) no querrán que los usuarios tengan que modificar directamente sus modelos para beneficiarse de ella.

Con django-mptt , por ejemplo, utilicé la pre_saveseñal para administrar un conjunto de campos que describen una estructura de árbol para el modelo que está a punto de crearse o actualizarse y la pre_deleteseñal para eliminar los detalles de la estructura de árbol para el objeto que se está eliminando y su totalidad subárbol de objetos antes de él y se eliminan. Debido a la utilización de señales, los usuarios no tienen que añadir o modificar saveo deletemétodos en sus modelos para tener esta gestión hecho por ellos, sólo tienen que dar a conocer django-MPTT qué modelos lo quieren manejar.

Jonny Buchanan
fuente
¿Qué pasa si el manejador de señales activa una excepción? Supongo que no deberían activar excepciones, o de lo contrario no encajan bien. ¿Me equivoco?
x-yuri
20

Tu preguntaste:

¿Habría algún beneficio al usar el despachador de señales de Django?

Encontré esto en los documentos de django:

Los métodos de modelo anulados no se llaman en operaciones masivas

Tenga en cuenta que el método delete () para un objeto no se llama necesariamente cuando se eliminan objetos de forma masiva mediante un QuerySet o como resultado de una eliminación en cascada. Para garantizar que se ejecute la lógica de eliminación personalizada, puede utilizar las señales pre_delete y / o post_delete.

Desafortunadamente, no existe una solución alternativa al crear o actualizar objetos de forma masiva, ya que no se llama a save (), pre_save ni post_save.

De: Anulación de métodos de modelo predefinidos

guettli
fuente
3
La vista de lista de administración de Django usa eliminación masiva ... estaba confundido hasta que encontré este tidbit.
N.Balauro
7
también dice "Desafortunadamente, no hay una solución alternativa al crear o actualizar objetos de forma masiva, ya que no se llama a save (), pre_save y post_save". - así que no creo que esto sea una compensación entre estos métodos.
Cory
Esto se aplica a ambos métodos, entonces la respuesta es: "no, no hay ningún beneficio en usar señales en lugar de anular el savemétodo".
Flimm
3

Si usa señales, podrá actualizar la puntuación de revisión cada vez que se guarde el modelo de puntuación relacionado. Pero si no necesito tal funcionalidad, no veo ninguna razón para poner esto en señal, eso es bastante relacionado con el modelo.

Dmitry Shevchenko
fuente
2

Es una especie de desnormalización. Mira esta bonita solución . Definición del campo de composición in situ.

Alex Koshelev
fuente
1

Pequeña adición de los documentos de Django sobre eliminación masiva ( .delete()método en QuerySetobjetos):

Tenga en cuenta que esto, siempre que sea posible, se ejecutará exclusivamente en SQL, por lo que los métodos delete () de instancias de objetos individuales no necesariamente se llamarán durante el proceso. Si proporcionó un método delete () personalizado en una clase de modelo y desea asegurarse de que se llame, deberá eliminar "manualmente" las instancias de ese modelo (por ejemplo, iterando sobre un QuerySet y llamando a delete () en cada objeto individualmente) en lugar de usar el método delete () masivo de un QuerySet.

https://docs.djangoproject.com/en/1.11/topics/db/queries/#deleting-objects

Y actualización masiva ( .update()método en QuerySetobjetos):

Finalmente, tenga en cuenta que update () realiza una actualización a nivel SQL y, por lo tanto, no llama a ningún método save () en sus modelos, ni emite las señales pre_save o post_save (que son una consecuencia de llamar a Model.save ( )). Si desea actualizar un grupo de registros para un modelo que tiene un método save () personalizado, recorralos y llame a save ()

https://docs.djangoproject.com/en/2.1/ref/models/querysets/#update

valex
fuente
¿No se aplica esto a ambos?
Flimm