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?
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.
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
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
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.
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
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
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
utilisez plutôt pk au lieu de id:
if not self.pk:
do_something()
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 :)
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
Cela fonctionnerait-il pour tous les scénarios ci-dessus?
if self.pk is not None and <ModelName>.objects.filter(pk=self.pk).exists():
...