sélectionner et mettre à jour l'enregistrement de la base de données avec un seul jeu de requêtes

140

Comment exécuter une instruction updateand selectsur le même querysetplutôt que de devoir faire deux requêtes: - une pour sélectionner l'objet - et une pour mettre à jour l'objet

L'équivalent en SQL serait quelque chose comme:

update my_table set field_1 = 'some value' where pk_field = some_value
John
la source

Réponses:

269

Utilisez la méthode d' objetupdate queryset :

MyModel.objects.filter(pk=some_value).update(field1='some value')
Daniel Roseman
la source
95
Juste un avertissement ... si vous utilisez la updateméthode comme celle-ci, aucun signal attaché à ce modèle ou autre "code" ne fonctionnera contre les objets. Juste un pointeur de quelqu'un qui a été brûlé :)
DMac the Destroyer
@DMactheDestroyer mec merci pour cette information précieuse. Devrions-nous alors utiliser l'ancienne méthode de mise à jour? (ie) obtenir et enregistrer?
@learning well mec, tout dépend de votre scénario. La updateméthode est idéale pour les mises à jour de masse, mais elle devrait déclencher un avertissement dans votre tête lorsque vous l'utilisez que vous devez examiner tous les signaux attachés à cet objet qui pourraient également avoir besoin d'être déclenchés manuellement
DMac the Destroyer
3
Est-il possible d'accéder à l'instance de modèle actuelle dans la fonction de mise à jour? commeMyModel.objects.filter(pk=some_value).update(field1=self.data)
Dipak
8
@DipakChandranP Vous devriez poser une nouvelle question plutôt que de mettre des commentaires sur une de six ans. Mais les expressions F () sont probablement ce que vous voulez.
Daniel Roseman le
70

Les objets de base de données Django utilisent la même méthode save () pour créer et modifier des objets.

obj = Product.objects.get(pk=pk)
obj.name = "some_new_value"
obj.save()

Comment Django sait UPDATE ou INSERT
Si l'attribut de clé primaire de l'objet est défini sur une valeur qui prend la valeur True (c'est-à-dire une valeur autre que None ou la chaîne vide), Django exécute un UPDATE. Si l'attribut de clé primaire de l'objet n'est pas défini ou si UPDATE n'a rien mis à jour, Django exécute un INSERT.

Réf .: https://docs.djangoproject.com/fr/1.9/ref/models/instances/

Slipstream
la source
17

Cette réponse compare les deux approches ci-dessus. Si vous souhaitez mettre à jour de nombreux objets sur une seule ligne, optez pour:

# Approach 1
MyModel.objects.filter(field1='Computer').update(field2='cool')

Sinon, vous devrez parcourir l'ensemble de requêtes et mettre à jour des objets individuels:

#Approach 2    
objects = MyModel.objects.filter(field1='Computer')
for obj in objects:
    obj.field2 = 'cool'
    obj.save()
  1. L'approche 1 est plus rapide car elle n'effectue qu'une seule requête de base de données, par rapport à l'approche 2 qui effectue des requêtes de base de données «n + 1». (Pour n éléments de l'ensemble de requêtes)

  2. La première approche fait une requête db, c'est-à-dire UPDATE, la seconde en fait deux: SELECT puis UPDATE.

  3. Le compromis est que, supposons que vous ayez des déclencheurs, comme la mise à jour updated_onou tout autre champ connexe, il ne sera pas déclenché lors de la mise à jour directe, c'est-à-dire de l'approche 1.

  4. L'approche 1 est utilisée sur un jeu de requêtes, il est donc possible de mettre à jour plusieurs objets à la fois, pas dans le cas de l'approche 2.

Pranche Tiwari
la source
Concernant 1. - Je pense que le résultat de la requête est mis en cache lors du premier appel à la requête, il n'y a donc en fait qu'un seul appel à DB.
user2340939
2

seulement dans un cas dans les serializerchoses, vous pouvez mettre à jour de manière très simple!

my_model_serializer = MyModelSerializer(
    instance=my_model, data=validated_data)
if my_model_serializer.is_valid():

    my_model_serializer.save()

seulement dans un cas dans les formchoses!

instance = get_object_or_404(MyModel, id=id)
form = MyForm(request.POST or None, instance=instance)
if form.is_valid():
    form.save()
Jamil Noyda
la source
Je pense que les sérialiseurs proviennent de Djanog Rest Framework et non de Django proprement dit.
Code-Apprentice
1
Ouais, cependant, Django formvient de Django Proper.
Jamil Noyda le