J'ai une fonction qui appelle actuellement Models.object.get()
qui renvoie soit 0 soit 1 objet modèle. S'il renvoie 0, je crée une nouvelle instance de modèle dans le fichier except DoesNotExist
de la fonction. Sinon, je voudrais mettre à jour les champs dans l'instance préexistante, sans en créer une nouvelle. À l'origine, j'essayais d'appeler .update()
sur l'instance qui a été trouvée, mais .update()
semble ne pouvoir être appelé que sur un QuerySets. Comment puis-je modifier une douzaine de champs, sans appeler .filter()
et en comparant les longueurs pour savoir si je dois créer ou mettre à jour une instance préexistante ?
Réponses
Trop de publicités?Avec l'arrivée de la version 1.7 de Django, il existe désormais une nouvelle fonction update_or_create
La méthode QuerySet, qui devrait faire exactement ce que vous voulez. Faites simplement attention aux conditions de course potentielles si l'unicité n'est pas appliquée au niveau de la base de données.
Exemple tiré de la documentation :
obj, created = Person.objects.update_or_create(
first_name='John', last_name='Lennon',
defaults={'first_name': 'Bob'},
)
En
update_or_create
La méthode tente de récupérer un objet dans la base de données. en fonction de l'information kwargs . Si une correspondance est trouvée, il met à jour le champs transmis dans la méthodedefaults
dictionnaire.
Pré-Django 1.7 :
Modifiez les valeurs des champs du modèle comme il convient, puis appelez .save()
pour maintenir les changements :
try:
obj = Model.objects.get(field=value)
obj.field = new_value
obj.save()
except Model.DoesNotExist:
obj = Model.objects.create(field=new_value)
# do something else with obj if need be
À partir de Django 1.5, il existe une propriété update_fields sur l'enregistrement du modèle, par exemple :
obj.save(update_fields=['field1', 'field2', ...])
https://docs.djangoproject.com/en/dev/ref/models/instances/
Je préfère cette approche car elle ne crée pas de problème d'atomicité si vous avez plusieurs instances d'applications Web qui modifient différentes parties d'une instance de modèle.
Voici une mixine que vous pouvez intégrer à n'importe quelle classe de modèle et qui donne à chaque instance un nom d'utilisateur et un mot de passe. update
méthode :
class UpdateMixin(object):
def update(self, **kwargs):
if self._state.adding:
raise self.DoesNotExist
for field, value in kwargs.items():
setattr(self, field, value)
self.save(update_fields=kwargs.keys())
En self._state.adding
vérifie si le modèle est enregistré dans la base de données et, si ce n'est pas le cas, soulève une erreur.
_(Note : Cette update
est utilisée lorsque vous souhaitez mettre à jour un modèle et que vous savez que l'instance est déjà enregistrée dans la base de données, ce qui répond directement à la question initiale. La méthode intégrée update_or_create
présentée dans la réponse de Platinum Azure couvre déjà l'autre cas d'utilisation)._
Vous l'utiliserez comme suit (après l'avoir intégré à votre modèle d'utilisateur) :
user = request.user
user.update(favorite_food="ramen")
En plus d'avoir une API plus agréable, un autre avantage de cette approche est qu'elle appelle la fonction pre_save
y post_save
tout en évitant les problèmes d'atomicité si un autre processus met à jour le même modèle.
- Réponses précédentes
- Plus de réponses