I'm writing a Django app, and I need a function to update a field in the database. Is there any reason to do one of these methods rather than the other?
def save_db_field(name,field,value): obj = MyModel.objects.get(name=name) obj.field = value obj.save() def update_db_field(name,field,value): MyModel.objects.get(name=name).update(field=value)
It seems like the second is better because it does it in one DB call instead of two. Is there a reason why fetching, then updating is any better?
To save changes to an object that's already in the database, use save() . This performs an UPDATE SQL statement behind the scenes. Django doesn't hit the database until you explicitly call save() .
The doc says: 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 link.
Use update_fields in save() If you would like to explicitly mention only those columns that you want to be updated, you can do so using the update_fields parameter while calling the save() method. You can also choose to update multiple columns by passing more field names in the update_fields list.
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()
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With