Django: Calling .Update() on a Single Model Instance Retrieved by .Get()

Django: Calling .update() on a single model instance retrieved by .get()?

With the advent of Django 1.7, there is now a new update_or_create QuerySet method, which should do exactly what you want. Just be careful of potential race conditions if uniqueness is not enforced at the database level.

Example from the documentation:

obj, created = Person.objects.update_or_create(
first_name='John', last_name='Lennon',
defaults={'first_name': 'Bob'},
)

The update_or_create method tries to fetch an object from database
based on the given kwargs. If a match is found, it updates the
fields passed in the defaults dictionary.


Pre-Django 1.7:

Change the model field values as appropriate, then call .save() to persist the changes:

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

How to select a record and update it, with a single queryset in Django?

Use the queryset object update method:

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

Run a django update but call the save method

The best way to do this is to just call save() directly. You will need to call get() instead of filter(), though.

Asset.objects.get(pk=asset.pk).save(update_fields=item)

This isn't a problem since your existing filter() is guaranteed to return a queryset with at most one Asset anyway. You just have to be sure that the given pk actually exists or wrap the get() call in a try...except block.

But...since you already have the Asset instance in asset, there's no reason to waste time with a DB query. Just call save directly on the object you have:

asset.save(update_fields=item)

Django updating a single model

I would recommend updating the proper way using the save method. Maybe you can move you code from pre-save to post-save and check for the created flag. Or overload the save method and do what you have to do there. Another idea would be doing something like this:

User.objects.filter(pk=1)[0:1].update()

This slicing syntax returns a QuerySet upon which you can call your update method. You could call it without even without slicing, but then you yould theoretically update more than just your one model by mistake. Unless you filter by a primary key or something unique, that is.

Overloading the save method:

class MyModel(models.Model):

def save(self, some_value, *args, **kwargs):
# do your pre-save stuff here
super(MyModel, self).save(*args, **kwargs)

If need be you could even return from the save method or throw an excepption before calling the original save method. Then the model would not save. I don't think it is possible to do something like passing parameters from the save method to the signals. You can, however, pass additional parameters to the save method and then ommit them when calling the super method (I updated the example).

How to avoid retrieving instance to update field in Django

You can do this using F expressions. You can use this with queries and with (or without) update and everything will take place at the SQL level.

Example from the docs:

from django.db.models import F
reporter = Reporters.objects.filter(name='Tintin')
reporter.update(stories_filed=F('stories_filed') + 1)

Django update only blank rows in model instance

Find one column which is always present, which also can be considered as unique on database (consider LogicalKey column).

for entry in entries:
try:
record = Model.objects.get(logical_key = entry['logical_key')
for k,v in entry.items():
if record._meta.get_field(k) is None:
setattr(record,k,v)
record.save()
except:
Model.objects.create(field1=entry['field1'],...)

How to update multiple fields of a django model instance?

It's tempting to mess with __dict__, but that won't apply to attributes inherited from a parent class.

You can either iterate over the dict to assign to the object:

for (key, value) in my_data_dict.items():
setattr(obj, key, value)
obj.save()

Or you can directly modify it from a queryset (making sure your query set only returns the object you're interested in):

FooModel.objects.filter(whatever="anything").update(**my_data_dict)

Django: save() vs update() to update the database?

There are several key differences.

update is used on a queryset, so it is possible to update multiple objects at once.

As @FallenAngel pointed out, there are differences in how custom save() method triggers, but it is also important to keep in mind signals and ModelManagers. I have build a small testing app to show some valuable differencies. I am using Python 2.7.5, Django==1.7.7 and SQLite, note that the final SQLs may vary on different versions of Django and different database engines.

Ok, here's the example code.

models.py:

from __future__ import print_function
from django.db import models
from django.db.models import signals
from django.db.models.signals import pre_save, post_save
from django.dispatch import receiver

__author__ = 'sobolevn'

class CustomManager(models.Manager):
def get_queryset(self):
super_query = super(models.Manager, self).get_queryset()
print('Manager is called', super_query)
return super_query


class ExtraObject(models.Model):
name = models.CharField(max_length=30)

def __unicode__(self):
return self.name


class TestModel(models.Model):

name = models.CharField(max_length=30)
key = models.ForeignKey('ExtraObject')
many = models.ManyToManyField('ExtraObject', related_name='extras')

objects = CustomManager()

def save(self, *args, **kwargs):
print('save() is called.')
super(TestModel, self).save(*args, **kwargs)

def __unicode__(self):
# Never do such things (access by foreing key) in real life,
# because it hits the database.
return u'{} {} {}'.format(self.name, self.key.name, self.many.count())


@receiver(pre_save, sender=TestModel)
@receiver(post_save, sender=TestModel)
def reicever(*args, **kwargs):
print('signal dispatched')

views.py:

def index(request):
if request and request.method == 'GET':

from models import ExtraObject, TestModel

# Create exmple data if table is empty:
if TestModel.objects.count() == 0:
for i in range(15):
extra = ExtraObject.objects.create(name=str(i))
test = TestModel.objects.create(key=extra, name='test_%d' % i)
test.many.add(test)
print test

to_edit = TestModel.objects.get(id=1)
to_edit.name = 'edited_test'
to_edit.key = ExtraObject.objects.create(name='new_for')
to_edit.save()

new_key = ExtraObject.objects.create(name='new_for_update')
to_update = TestModel.objects.filter(id=2).update(name='updated_name', key=new_key)
# return any kind of HttpResponse

That resuled in these SQL queries:

# to_edit = TestModel.objects.get(id=1):
QUERY = u'SELECT "main_testmodel"."id", "main_testmodel"."name", "main_testmodel"."key_id"
FROM "main_testmodel"
WHERE "main_testmodel"."id" = %s LIMIT 21'
- PARAMS = (u'1',)

# to_edit.save():
QUERY = u'UPDATE "main_testmodel" SET "name" = %s, "key_id" = %s
WHERE "main_testmodel"."id" = %s'
- PARAMS = (u"'edited_test'", u'2', u'1')

# to_update = TestModel.objects.filter(id=2).update(name='updated_name', key=new_key):
QUERY = u'UPDATE "main_testmodel" SET "name" = %s, "key_id" = %s
WHERE "main_testmodel"."id" = %s'
- PARAMS = (u"'updated_name'", u'3', u'2')

We have just one query for update() and two for save().

Next, lets talk about overriding save() method. It is called only once for save() method obviously. It is worth mentioning, that .objects.create() also calls save() method.

But update() does not call save() on models. And if no save() method is called for update(), so the signals are not triggered either. Output:

Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

# TestModel.objects.get(id=1):
Manager is called [<TestModel: edited_test new_for 0>]
Manager is called [<TestModel: edited_test new_for 0>]
save() is called.
signal dispatched
signal dispatched

# to_update = TestModel.objects.filter(id=2).update(name='updated_name', key=new_key):
Manager is called [<TestModel: edited_test new_for 0>]

As you can see save() triggers Manager's get_queryset() twice. When update() only once.

Resolution. If you need to "silently" update your values, without save() been called - use update. Usecases: last_seen user's field. When you need to update your model properly use save().



Related Topics



Leave a reply



Submit