web-dev-qa-db-fra.com

Django signaux vs méthode de sauvegarde prioritaire

J'ai du mal à envelopper ma tête autour de ça. En ce moment, j'ai quelques modèles qui ressemblent un peu à 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 comporte plusieurs "scores", le score global est la moyenne des scores. Lorsqu'un avis ou un score est enregistré, je dois recalculer la moyenne de la note globale. En ce moment, j'utilise une méthode de sauvegarde surchargée. Y aurait-il des avantages à utiliser le répartiteur de signaux de Django?

85
imjoevasquez

Les signaux d'enregistrement/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 qui pourraient être configurées pour être utilisées entre plusieurs modèles.

Une tâche courante dans les méthodes save 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 aviez besoin de l'implémenter pour un certain nombre de modèles, gagnerait à utiliser un pre_save signal, où le gestionnaire de signal pourrait prendre le nom du champ de 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 la limace que vous êtes sur le point d'ajouter pour le type de modèle en question, afin d'assurer l'unicité.

Les applications réutilisables bénéficient souvent de l'utilisation de signaux - si les fonctionnalités qu'elles fournissent peuvent être appliquées à n'importe quel modèle, elles ne veulent généralement pas (sauf si cela 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_save signal pour gérer un ensemble de champs qui décrivent une structure arborescente pour le modèle qui est sur le point d'être créé ou mis à jour et le pre_delete signal pour supprimer les détails de la structure arborescente de l'objet en cours de suppression et de l'ensemble de sa sous-arborescence d'objets avant et ils sont supprimés. En raison de l'utilisation de signaux, les utilisateurs n'ont pas besoin d'ajouter ou de modifier les méthodes save ou delete sur leurs modèles pour que cette gestion soit faite pour eux, ils n'ont qu'à informer Django-mptt quels modèles ils veulent qu'il gère.

81
Jonny Buchanan

Tu as demandé:

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

J'ai trouvé cela dans les documents 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 () pour 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’existe pas de solution de contournement lors de la création ou de la mise à jour d’objets en bloc, car aucun des enregistrements save (), pre_save et post_save n’est appelé.

De: remplacement des méthodes de modèle prédéfinies

18
guettli

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

3

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

2
Alex Koshelev

Petit ajout de Django docs sur la suppression en masse (méthode .delete() sur les objets QuerySet):

Gardez à l'esprit que cela sera, autant que 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 de suppression en bloc () d'un QuerySet.

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

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

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 ensemble d'enregistrements pour un modèle doté d'une méthode save () personnalisée, bouclez-les et appelez save ()

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

1
valex