Signaux Django et méthode de sauvegarde prioritaire

89

J'ai du mal à comprendre ça. En ce moment, j'ai des modèles qui ressemblent à ceci:

 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()

Un examen a plusieurs «scores», le score global est la moyenne des scores. Lorsqu'un avis ou un score est enregistré, je dois recalculer la moyenne de global_score. En ce moment, j'utilise une méthode de sauvegarde remplacée. Y aurait-il des avantages à utiliser le répartiteur de signaux de Django?

imjoevasquez
la source

Réponses:

84

Les signaux d'enregistrement / de suppression sont généralement favorables dans les situations où vous devez apporter des modifications qui ne sont pas complètement spécifiques au modèle en question, ou qui pourraient être appliquées à des modèles qui ont quelque chose en commun, ou pourraient être configurés pour une utilisation dans plusieurs modèles.

Une tâche courante dans les saveméthodes remplacées est la génération automatisée de slugs à partir d'un champ de texte dans un modèle. C'est un exemple de quelque chose qui, si vous deviez l'implémenter pour un certain nombre de modèles, bénéficierait de l'utilisation d'un pre_savesignal, où le gestionnaire de signal pourrait prendre le nom du champ slug et le nom du champ à partir duquel générer le slug. Une fois que vous avez quelque chose comme ça en place, toute fonctionnalité améliorée que vous mettez en place s'appliquera également à tous les modèles - par exemple en recherchant le slug que vous êtes sur le point d'ajouter pour le type de modèle en question, pour assurer l'unicité.

Les applications réutilisables bénéficient souvent de l'utilisation de signaux - si la fonctionnalité qu'elles fournissent peut être appliquée à n'importe quel modèle, elles ne voudront généralement pas (sauf si c'est inévitable) que les utilisateurs doivent modifier directement leurs modèles pour en bénéficier.

Avec django-mptt , par exemple, j'ai utilisé le pre_savesignal pour gérer un ensemble de champs qui décrivent une arborescence pour le modèle qui est sur le point d'être créé ou mis à jour et le pre_deletesignal pour supprimer les détails de l'arborescence de l'objet à supprimer et son ensemble sous-arborescence d'objets devant lui et ils sont supprimés. En raison de l'utilisation de signaux, les utilisateurs ne pas ajouter ou modifier saveou deletesavoir méthodes ont sur leurs modèles pour cette gestion fait pour eux, ils ont juste de laisser django-MPTT quels modèles ils le veulent gérer.

Jonny Buchanan
la source
Que faire si le gestionnaire de signaux déclenche une exception? Je suppose qu'ils ne devraient pas déclencher d'exceptions, sinon ils ne conviennent pas. Ai-je tort?
x-yuri
20

Tu as demandé:

Y aurait-il des avantages à utiliser le répartiteur de signaux de Django?

J'ai trouvé ceci dans la documentation django:

Les méthodes de modèle remplacées ne sont pas appelées sur les opérations en bloc

Notez que la méthode delete () d'un objet n'est pas nécessairement appelée lors de la suppression d'objets en bloc à l'aide d'un QuerySet ou à la suite d'une suppression en cascade. Pour garantir l'exécution de la logique de suppression personnalisée, vous pouvez utiliser des signaux pre_delete et / ou post_delete.

Malheureusement, il n'y a pas de solution de contournement lors de la création ou de la mise à jour d'objets en masse, car aucune des fonctions save (), pre_save et post_save n'est appelée.

From: Remplacement des méthodes de modèle prédéfinies

guettli
la source
3
La vue de la liste des administrateurs de Django utilise la suppression en masse ... était confuse jusqu'à ce que je tombe sur cette friandise.
N.Balauro
7
il dit aussi "Malheureusement, il n'y a pas de solution de contournement lors de la création ou de la mise à jour d'objets en masse, car aucun des save (), pre_save et post_save n'est appelé." - donc je ne pense pas que ce soit un compromis entre ces méthodes.
Cory du
Cela s'applique aux deux méthodes, la réponse est donc: "non, il n'y a aucun avantage à utiliser des signaux par opposition à remplacer la saveméthode"?
Flimm
3

Si vous utilisez des signaux, vous pourrez mettre à jour le score d'examen chaque fois que le modèle de score associé est enregistré. Mais si je n'ai pas besoin d'une telle fonctionnalité, je ne vois aucune raison de mettre cela en signal, c'est assez lié au modèle.

Dmitry Shevchenko
la source
2

C'est une sorte de dénormalisation. Regardez cette jolie solution . Définition du champ de composition sur place.

Alex Koshelev
la source
1

Petit ajout de la documentation Django sur la suppression en bloc ( .delete()méthode sur les QuerySetobjets):

Gardez à l'esprit que cela sera, dans la mesure du possible, exécuté uniquement en SQL, et donc les méthodes delete () des instances d'objet individuelles ne seront pas nécessairement appelées pendant le processus. Si vous avez fourni une méthode delete () personnalisée sur une classe de modèle et que vous voulez vous assurer qu'elle est appelée, vous devrez supprimer «manuellement» les instances de ce modèle (par exemple, en itérant sur un QuerySet et en appelant delete () sur chaque objet individuellement) plutôt que d'utiliser la méthode bulk delete () d'un QuerySet.

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

Et mise à jour en masse ( .update()méthode sur les QuerySetobjets):

Enfin, sachez que update () effectue une mise à jour au niveau SQL et, par conséquent, n'appelle aucune méthode save () sur vos modèles, ni n'émet les signaux pre_save ou post_save (qui sont une conséquence de l'appel de Model.save ( )). Si vous souhaitez mettre à jour un tas d'enregistrements pour un modèle qui a une méthode save () personnalisée, bouclez dessus et appelez save ()

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

Valex
la source
Cela ne s'applique-t-il pas aux deux?
Flimm