Issue
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?
Solution
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()
.
Answered By - sobolevn
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.