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?

123
demandé sur MikeN 2009-05-25 22:45:28

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.

158
répondu Dave W. Smith 2017-03-17 14:54:08

Autre façon de vérifier self.pk, nous pouvons vérifier self._state du modèle

self._state.adding is True la création de

self._state.adding is False mise à jour

Je l'ai obtenu de cette page

83
répondu SaintTail 2018-03-26 21:23:23

Vérification de self.id suppose que id est la clé primaire pour le modèle. Une manière plus générique serait d'utiliser le raccourci PK .

is_new = self.pk is None

41
répondu Gerry 2009-05-27 03:41:36

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.

36
répondu KayEss 2009-06-02 17:45:36

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

8
répondu JF Simon 2017-10-31 19:19:24

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

7
répondu Kwaw Annor 2014-07-23 17:10:33

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

5
répondu Jordan 2015-04-27 18:57:46

Utiliser pk au lieu de id:

if not self.pk:
  do_something()
3
répondu yedpodtrzitko 2009-12-04 22:51:00

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

2
répondu metakermit 2017-03-23 15:38:18

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

1
répondu vikingosegundo 2009-05-25 18:50:14

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

-3
répondu ha22109 2013-10-03 10:00:45