218

How do I run an update and select statements on the same queryset rather than having to do two queries: - one to select the object - and one to update the object

The equivalent in SQL would be something like:

update my_table set field_1 = 'some value' where pk_field = some_value
ivanleoncz
  • 9,070
  • 7
  • 57
  • 49
John
  • 21,047
  • 43
  • 114
  • 155

8 Answers8

440

Use the queryset object update method:

MyModel.objects.filter(pk=some_value).update(field1='some value')
Adolfo
  • 1,315
  • 2
  • 14
  • 22
Daniel Roseman
  • 588,541
  • 66
  • 880
  • 895
  • 163
    Just a fair warning... if you use the `update` method like this then any signals attached to that model or other "code stuff" won't run against the objects. Just a pointer from someone who got burned :) – DMac the Destroyer Jan 26 '12 at 06:01
  • @DMactheDestroyer dude thanks for that valuable info. Then should we use the older way of updating it? (ie) get and save? –  Jul 17 '15 at 05:39
  • 5
    @learning well dude, it all depends on your scenario. The `update` method is great for mass updates, but it should set off a warning in your head when you use it that you need to review any signals attached to that object that might also need to be manually fired – DMac the Destroyer Jul 17 '15 at 15:19
  • 4
    Is it possible to access the current model instance in the update function? like `MyModel.objects.filter(pk=some_value).update(field1=self.data)` – Dipak Jun 29 '16 at 07:56
  • 14
    @DipakChandranP You should ask a new question rather than putting comments on a six-year-old one. But F() expressions are probably want you want. – Daniel Roseman Jun 29 '16 at 08:05
  • Why this method is not updating Image Field?? [link](https://stackoverflow.com/questions/54040591/django-imagefield-is-not-updating-when-update-method-is-used) – Jayesh Singh Jan 05 '19 at 14:15
  • 1
    it is worth noting that, `filter()` may return multiple queries if a unique key is not used to filter. In this case, the `update()` will do a bulk update by updating all queries returned. So, I think in some point, it is better to use the `get()` then `save()` if we want to be sure that only a single unique query is updated. – Eyong Kevin Enowanyo Dec 03 '21 at 14:00
  • @EyongKevinEnowanyo If you have a primary key or otherwise know that it will return only 1 record, the `update()` is much faster since it only has to do 1 remote query instead of 2. – Matthew Moisen Feb 09 '22 at 01:40
  • 4
    @DMactheDestroyer 9 years later, I finally understand your comment. https://stackoverflow.com/a/71688507/417899 – cyberfly Mar 31 '22 at 07:37
  • How to `.update` only the _first_ record in the query? – Love Putin Not War Jun 04 '22 at 05:36
  • `.update()` doesn't works with `.get()` – Talha Asghar Oct 09 '22 at 18:04
127

Django database objects use the same save() method for creating and changing objects.

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

How Django knows to UPDATE vs. INSERT
If the object’s primary key attribute is set to a value that evaluates to True (i.e., a value other than None or the empty string), Django executes an UPDATE. If the object’s primary key attribute is not set or if the UPDATE didn’t update anything, Django executes an INSERT.

Ref.: https://docs.djangoproject.com/en/1.9/ref/models/instances/

Slipstream
  • 13,455
  • 3
  • 59
  • 45
32

This answer compares the above two approaches. If you want to update many objects in a single line, go for:

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

Otherwise you would have to iterate over the query set and update individual objects:

#Approach 2    
objects = MyModel.objects.filter(field1='Computer')
for obj in objects:
    obj.field2 = 'cool'
    obj.save()
  1. Approach 1 is faster because, it makes only one database query, compared to approach 2 which makes 'n+1' database queries. (For n items in the query set)

  2. Fist approach makes one db query ie UPDATE, the second one makes two: SELECT and then UPDATE.

  3. The tradeoff is that, suppose you have any triggers, like updating updated_on or any such related fields, it will not be triggered on direct update ie approach 1.

  4. Approach 1 is used on a queryset, so it is possible to update multiple objects at once, not in the case of approach 2.

Pransh Tiwari
  • 3,983
  • 1
  • 32
  • 43
27

1st method

MyTable.objects.filter(pk=some_value).update(field1='some value')

2nd Method

q = MyModel.objects.get(pk=some_value)
q.field1 = 'some value'
q.save()

3rd method

By using get_object_or_404

q = get_object_or_404(MyModel,pk=some_value)
q.field1 = 'some value'
q.save()

4th Method

if you required if pk=some_value exist then update it other wise create new one by using update_or_create.

MyModel.objects.update_or_create(pk=some_value,defaults={'field1':'some value'})
Riyas Ac
  • 1,553
  • 1
  • 9
  • 23
  • I want to use method #2 but with `q["field1"] = 'some value'`... however, I get the error "TypeError: 'User' object does not support item assignment" -- is there another way to do this? I have the field name in a variable – ekkis Sep 07 '22 at 01:13
5

If you need to set the new value based on the old field value that is do something like:

update my_table set field_1 = field_1 + 1 where pk_field = some_value

use query expressions:

MyModel.objects.filter(pk=some_value).update(field1=F('field1') + 1)

This will execute update atomically that is using one update request to the database without reading it first.

2

only in a case in serializer things, you can update in very simple way!

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

    my_model_serializer.save()

only in a case in form things!

instance = get_object_or_404(MyModel, id=id)
form = MyForm(request.POST or None, instance=instance)
if form.is_valid():
    form.save()
Jamil Noyda
  • 3,321
  • 2
  • 21
  • 26
1

Accepted answer works great, but it comes with some unwanted side effect.

For example, you are using imageField, the update() will work and update others data, but not update your imageField data

class ProfileSetting(models.Model):

    first_name = models.CharField(blank=True)

    logo = models.ImageField(blank=True, null=True, upload_to="profile/logo/")

update_data = {
  "first_name": "john",
  "logo": request.FILES['logo'] # logo will not be properly update
}

ProfileSetting.objects.filter(pk=some_value).update(**update_data)

Here is some example with good explanation Django ImageField is not updating when update() method is used

cyberfly
  • 5,568
  • 8
  • 50
  • 67
0

Above mentioned answer works great, but it happens with some unwanted side effect, so to avoid such errors writes your db code inside exception blocks.

    try:
        obj = <Your_Model_Name>.objects.get(PK=<pk_id>)
        obj.name = req.POST.get("name")
        obj.save()
    except Exception as e:
        print(e)
Ashish Gupta
  • 1,153
  • 12
  • 14