Dans une méthode django model custom save (), comment identifier un nouvel objet?
Je veux déclencher une action spéciale dans la méthode save () d'un objet modèle Django lorsque j'enregistre un nouvel enregistrement (ne mettant pas à jour un enregistrement existant.)
Est la vérification de (self.id != Aucun) nécessaire et suffisant pour garantir que l'auto-enregistrement est nouveau et n'est pas mis à jour? Des cas particuliers que cela pourrait négliger?
11 réponses
self.pk is None:
Renvoie True dans un nouvel objet modèle, sauf si l'objet a UUIDField
comme primary_key
.
Le cas de coin dont vous pourriez avoir à vous soucier est de savoir s'il existe des contraintes d'unicité sur les champs autres que l'id (par exemple, des index uniques secondaires sur d'autres champs). Dans ce cas, vous pourriez toujours avoir un nouvel enregistrement en main, mais ne pas pouvoir l'enregistrer.
La vérification de self.pk == None
est Pas suffisante pour déterminer si l'objet va être inséré ou mis à jour dans la base de données.
Le Django O/RM dispose d'un hack particulièrement méchant qui consiste essentiellement à vérifier s'il y a quelque chose à la position PK et si oui faire une mise à jour, sinon faire un INSERT (ceci est optimisé pour un INSERT si le Pk est None).
La raison pour laquelle il doit le faire est que vous êtes autorisé à définir le PK lorsqu'un objet est créé. Bien que pas commun lorsque vous avez une colonne de séquence pour la clé primaire, cela ne vaut pas pour les autres types de champ de clé primaire.
Si vous voulez vraiment savoir, vous devez faire ce que fait L'O / RM et regarder dans la base de données.
Bien sûr, vous avez un cas spécifique dans votre code et pour cela il est fort probable que self.pk == None
vous dise tout ce que vous devez savoir, mais ce n'est pas une solution générale.
Vous pouvez simplement vous connecter au signal post_save qui envoie un kwargs "créé", si vrai, votre objet a été inséré.
Http://docs.djangoproject.com/en/stable/ref/signals/#post-save
Vérifiez self.id
et l'indicateur force_insert
.
if not self.pk or kwargs.get('force_insert', False):
self.created = True
# call save method.
super(self.__class__, self).save(*args, **kwargs)
#Do all your post save actions in the if block.
if getattr(self, 'created', False):
# So something
# Do something else
C'est pratique car votre objet nouvellement créé (self) a pk
Valeur
Je suis très en retard à cette conversation, mais j'ai rencontré un problème avec le self.pk être rempli quand il a une valeur par défaut qui lui est associée.
La façon dont j'ai contourné cela est d'ajouter un champ date_created au modèle
date_created = models.DateTimeField(auto_now_add=True)
De là, vous pouvez aller
created = self.date_created is None
Utiliser pk au lieu de id:
if not self.pk:
do_something()
Pour une solution qui fonctionne également même lorsque vous avez un UUIDField
comme clé primaire (ce qui, comme d'autres l'ont noté, n'est pas None
Si vous remplacez simplement save
), vous pouvez vous brancher sur le signal post_save de Django. Ajoutez ceci à votre models.py:
from django.db.models.signals import post_save
from django.dispatch import receiver
@receiver(post_save, sender=MyModel)
def mymodel_saved(sender, instance, created, **kwargs):
if created:
# do extra work on your instance, e.g.
# instance.generate_avatar()
# instance.send_email_notification()
pass
Ce rappel bloquera la méthode save
, de sorte que vous pouvez faire des choses comme déclencher des notifications ou mettre à jour le modèle avant que votre réponse ne soit renvoyée sur le fil, que vous utilisiez forms ou le framework Django REST pour AJAX appeler. Bien sûr, utilisez de manière responsable et déchargez les tâches lourdes dans une file d'attente au lieu de faire attendre vos utilisateurs:)
C'est la manière courante de le faire.
L'id sera donné lors de la première sauvegarde dans la base de données
Pour savoir si vous mettez à jour ou insérez l'objet (données), utilisez self.instance.fieldname
dans votre formulaire. Définissez une fonction propre dans votre formulaire et vérifiez si l'entrée de valeur actuelle est la même que la précédente, sinon vous la mettez à jour.
self.instance
et self.instance.fieldname
comparer avec la nouvelle valeur