Je souhaite déclencher une action spéciale dans la méthode save () d'un objet de modèle Django lorsque j'enregistre un nouvel enregistrement (sans mettre à jour un enregistrement existant).
La vérification de (self.id! = None) est-elle nécessaire et suffisante pour garantir que l'enregistrement automatique est nouveau et n'est pas mis à jour? Y a-t-il des cas particuliers que cela pourrait négliger?
django
django-models
MikeN
la source
la source
UUIDField pk
Réponses:
Mise à jour: avec la clarification qui
self._state
n'est pas une variable d'instance privée, mais nommée de cette façon pour éviter les conflits, la vérificationself._state.adding
est désormais le moyen préférable de vérifier.renvoie True dans un nouvel objet Model, sauf si l'objet a
UUIDField
pourprimary_key
.Le cas du coin dont vous pourriez avoir à vous soucier est de savoir s'il existe des contraintes d'unicité sur des champs autres que l'identifiant (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.
la source
is not
plutôt que!=
lors de la vérification de l'identité avec l'None
objetmodels.OneToOneField(OtherModel, primary_key=True)
. Je pense que vous devez utiliserself.pk
UUIDField
comme clé primaire, ceself.pk
n'est jamaisNone
.Autre moyen de vérifier que
self.pk
nous pouvons vérifierself._state
le modèleself._state.adding is True
créerself._state.adding is False
mise à jourJe l'ai eu sur cette page
la source
self._state.adding
fonctionne, mais juste avertissement qu'il semble toujours égalFalse
si vous le vérifiez après avoir appelésuper(TheModel, self).save(*args, **kwargs)
: github.com/django/django/blob/stable/1.10.x/django/db/models/ …_state
n'est pas privé; comme_meta
, il est précédé d'un trait de soulignement pour éviter toute confusion avec les noms de champ. (Remarquez comment il est utilisé dans la documentation liée.)is_new = self._state.adding
, puissuper(MyModel, self).save(*args, **kwargs)
et puisif is_new: my_custom_logic()
La vérification
self.id
suppose qu'ilid
s'agit de la clé primaire du modèle. Une manière plus générique serait d'utiliser le raccourci pk .is_new = self.pk is None
la source
super(...).save()
.La vérification
self.pk == None
n'est pas suffisante pour déterminer si l'objet va être inséré ou mis à jour dans la base de données.Django O / RM propose un hack particulièrement méchant qui consiste essentiellement à vérifier s'il y a quelque chose à la position PK et si c'est le cas, faites une MISE À JOUR, sinon faites un INSERT (cela est optimisé en INSERT si le PK est Aucun).
La raison pour laquelle il doit faire cela est 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 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 cela
self.pk == None
vous dise tout ce que vous devez savoir, mais ce n'est pas une solution générale.la source
UUIDField
comme clé primaire: la clé n'est pas remplie au niveau de la base de données, elle l'self.pk
est toujoursTrue
.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
la source
ATOMIC_REQUESTS
, donc je ne suis pas vraiment sûr de la valeur par défaut.Vérifiez
self.id
et leforce_insert
drapeau.Ceci est pratique car votre objet nouvellement créé (soi) a de la
pk
valeurla source
Je suis très en retard à cette conversation, mais j'ai rencontré un problème avec le self.pk étant rempli quand il a une valeur par défaut qui lui est associée.
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
la source
Pour une solution qui fonctionne également même lorsque vous avez une
UUIDField
clé primaire (ce qui, comme d'autres l'ont noté, ne l'est pasNone
si vous remplacez simplementsave
), vous pouvez vous connecter au signal post_save de Django . Ajoutez ceci à votre models.py :Ce rappel bloquera la
save
méthode, vous pouvez donc 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 des formulaires ou le framework Django REST pour les appels AJAX. 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 :)la source
utilisez plutôt pk au lieu de id :
la source
C'est la manière courante de le faire.
l'identifiant sera donné lors de la première sauvegarde dans la base de données
la source
Cela fonctionnerait-il pour tous les scénarios ci-dessus?
la source
la source
Pour savoir si vous mettez à jour ou insérez l'objet (données), utilisez
self.instance.fieldname
dans votre formulaire. Définissez une fonction de nettoyage 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
etself.instance.fieldname
comparez avec la nouvelle valeurla source