web-dev-qa-db-fra.com

Dans une méthode Django model custom save (), comment identifier un nouvel objet?

Je souhaite déclencher une action spéciale dans la méthode save () d'un objet de modèle Django lorsque je sauvegarde un nouvel enregistrement (sans mettre à jour un enregistrement existant.)

Le chèque de (self.id! = None) est-il nécessaire et suffisant pour garantir que l'enregistrement personnel est nouveau et qu'il n'est pas mis à jour? Des cas particuliers que cela pourrait négliger?

146
MikeN
self.pk is None:

renvoie True dans un nouvel objet Model, sauf si l'objet a un UUIDField comme son primary_key.

Le cas qui vous préoccupe peut-être est de savoir s'il existe des contraintes d'unicité pour 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 être incapable de le sauvegarder.

183
Dave W. Smith

Autre moyen de vérifier self.pk on peut vérifier self._state du modèle

self._state.adding is True créer

self._state.adding is False mise à jour

Je l'ai eu de ceci page

139
SaintTail

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

is_new = self.pk is None

42
Gerry

Le chèque de self.pk == None est pas suffisant pour déterminer si l’objet va être inséré ou mis à jour dans la base de données.

Le Django O/RM comporte un bidouillage particulièrement méchant qui consiste essentiellement à vérifier si quelque chose se trouve à la position PK et si c'est le cas, faites une mise à jour, sinon faites un INSERT (cela optimise un INSERT). si le PK est Aucun).

Cela s'explique par le fait que vous êtes autorisé à définir le PK lorsqu'un objet est créé. Bien que cela ne soit pas courant lorsque vous avez une colonne de séquence pour la clé primaire, cela ne s'applique pas aux autres types de champs de clé primaire.

Si vous voulez vraiment savoir, vous devez faire ce que fait 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 dit tout ce que vous devez savoir, mais ce n'est pas une solution générale.

38
KayEss

Vous pouvez simplement vous connecter au signal post_save qui envoie un kwarg "créé", si true, votre objet a été inséré.

http://docs.djangoproject.com/fr/stable/ref/signals/#post-save

9
JF Simon

Vérifier self.id et le force_insert drapeau.

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

Ceci est pratique car votre objet nouvellement créé (self) a la valeur pk

7
Kwaw Annor

Je suis très en retard dans cette conversation, mais je suis tombé sur un problème avec le fichier self.pk en cours de remplissage lorsqu'il est associé à une valeur par défaut.

La façon dont j'ai contourné cela consiste à 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
Jordan

utilisez plutôt pk au lieu de id:

if not self.pk:
  do_something()
4
yedpodtrzitko

Pour une solution qui fonctionne également même lorsque vous avez une clé primaire UUIDField (qui, comme d'autres l'ont déjà noté, n'est pas None si vous remplacez simplement save), vous pouvez branchez 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 afin que vous puissiez effectuer des opérations telles que les notifications de déclenchement ou mettre à jour le modèle avant que votre réponse ne soit renvoyée par le réseau, que vous utilisiez des formulaires ou Django REST pour les appels AJAX. Bien sûr, utilisez de manière responsable et déchargez des tâches lourdes dans une file d'attente de tâches au lieu de laisser vos utilisateurs en attente :)

4
metakermit

C'est la manière habituelle de le faire.

l'identifiant sera donné lors de la première sauvegarde sur la base de données

1
vikingosegundo

Cela fonctionnerait-il pour tous les scénarios ci-dessus?

if self.pk is not None and <ModelName>.objects.filter(pk=self.pk).exists():
...
0
Sachin