Django post_save la prévention de la récursivité sans écraser modèle save()
Il y a beaucoup de Débordement de Pile messages au sujet de la récursivité à l'aide de la post_save
signal, dont les commentaires et les réponses sont en grande majorité: "pourquoi ne pas remplacer save()" ou save qui est seulement ouvert le feu sur created == True
.
Eh bien, je crois qu'il y a une bonne affaire pour ne pas utiliser save()
- par exemple, je suis l'ajout d'une application temporaire qui gère le traitement des commandes des données complètement séparée de notre modèle.
Le reste du cadre est au courant de la réalisation de l'application et l'utilisation de post_save crochets isolats toute l'exécution connexes code de notre modèle.
Si on laisse tomber l'accomplissement du service, rien à propos de notre code de base qui doit changer. Nous supprimons la réalisation de l'app, et c'est tout.
Donc, il y a aucune décent méthodes pour assurer la post_save signal n'est pas feu le gestionnaire de même deux fois?
- Est-ce juste une rumination, ou vous avez une situation particulière où vous avez observé plusieurs tirs de la même gestionnaire pour un événement unique? E. g.
save()
feuxpost_save
, ce qui entraîne une autre gestionnaire desave()
le même objet, et donc de provoquer un autre tir depost_save
? - oui, si votre post_save gestionnaire doit enregistrer l'expéditeur exemple, il va déclencher post_save de nouveau.
- lire ici avec bulk_create vous pouvez enregistrer sans postsave et presave appel django docs
Vous devez vous connecter pour publier un commentaire.
Ce que vous pensez de cette solution?
Vous pouvez également créer décorateur
instance.save()
avec n'importe quel nom inutilisé comme_dirty
. Ensuite, vérifiez si l'attribut existe et de briser la récursivité.Comme vous pouvez le voir nous avons mis_dirty
attribut avant de sauvegarder le modèle et l'enlever lors de l'enregistrement est terminé.try...finally
autour de l'appel àinstance.save()
pour s'assurer quedel instance._dirty
est toujours, même dans le cas, par exemple, deDatabaseError
.from functools import wraps
vous pouvez utiliser la mise à jour au lieu de l'enregistrer dans le gestionnaire de signal
save()
au lieu deupdate()
?Ne débranchez pas les signaux. Si un nouveau modèle de même type est générée lorsque le signal est déconnecté de la fonction de gestionnaire ne sera pas déclenché. Les signaux sont globales à travers Django et plusieurs demandes peuvent être en cours d'exécution simultanément, de sorte que certains échoue tandis que d'autres exécutent leurs post_save gestionnaire.
Je pense que la création d'un
save_without_signals()
méthode du modèle est plus explicite:__init__
, vous pourriez faireif not getattr(instance, '_disable_signals', False)
_disable_signals
propriété est local à chaque instance du modèle.instance.save(send_signal=False)
.Comment sur de déconnecter puis de reconnecter le signal à l'intérieur de votre
post_save
fonction:try...finally
. Doit faire de la (re)connect
à l'intérieur definally
clause. Sans cela, sido_stuff
ousave
soulever une exception alors votre gestionnaire de rester coupé à jamais...Vous devez utiliser queryset.mise à jour() à la place du Modèle.save (), mais vous devez prendre soin de quelque chose d'autre:
Il est important de noter que lorsque vous l'utilisez, si vous voulez utiliser les nouveaux objets, vous devriez obtenir son objet nouveau, parce qu'il ne changera pas l'autonomie de l'objet, par exemple:
Donc, si vous souhaitez utiliser le nouvel objet que vous devriez faire à nouveau:
Vous pouvez aussi vérifier les
raw
argument enpost_save
et ensuite appelersave_base
au lieu desave
.save_base
envoie le signal; passave
.raw=True
de lasave
méthode.Vérifier cela...
Chaque signal a ses propres avantages que vous pouvez lire à ce sujet dans les docs ici, mais je voulais partager un couple de choses à garder à l'esprit avec la pre_save et post_save signaux.
Les deux sont appelés à chaque fois .save() sur un modèle est appelé. En d'autres termes, si vous enregistrez le modèle de l'instance, les signaux sont envoyés.
l'exécution de la méthode save() sur l'instance au sein d'un post_save peut souvent créer une boucle sans fin, et donc provoquer un max profondeur de récursion dépassé erreur --- uniquement si vous n'utilisez pas .save() correctement.
pre_save est idéal pour la modification des données d'instance parce que vous n'avez pas à appeler save() jamais ce qui élimine la possibilité de ci-dessus. La raison pour laquelle vous n'avez pas à appeler save() c'est parce que un pre_save signal signifie littéralement droite avant d'être enregistré.
Signaux peuvent appeler d'autres signaux et ou exécuter retard de tâches (Céleri), qui peut être énorme pour la facilité d'utilisation.
Source: https://www.codingforentrepreneurs.com/blog/post-save-vs-pre-save-vs-override-save-method/
Ce qui concerne l'!!