Django:save()vs update()更新数据库? [英] Django: save() vs update() to update the database?

查看:246
本文介绍了Django:save()vs update()更新数据库?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写Django应用,我需要一个函数来更新数据库中的字段。

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)

似乎第二个更好,因为它在一个DB调用而不是两个DB调用中完成。

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?

推荐答案

有几个主要区别。

update 用于查询集,因此可以一次更新多个对象。

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

@FallenAngel 指出,自定义 save()的方式有所不同方法触发,但是记住 signals ModelManagers 也很重要。我构建了一个小型测试应用程序,以显示一些有价值的差异。我使用的是Python 2.7.5,Django == 1.7.7和SQLite,请注意,最终的SQL在不同版本的Django和不同的数据库引擎上可能会有所不同。

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.

好,这是示例代码。

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

在以下SQL查询中得到的结果:

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')

我们只有一个查询 update(),两个查询 save()

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

接下来,让我们讨论覆盖 save()方法。显然, save()方法仅调用一次。值得一提的是, .objects.create()也调用 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.

但是 update()不会调用 save()在模型上。而且,如果没有为 update()调用 save()方法,则也不会触发信号。输出:

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>]

您可以看到 save()触发 Manager get_queryset()两次。 update()仅一次。

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

分辨率。如果您需要静静地更新您的值,而无需调用 save(),请使用 update 。用例: last_seen 用户字段。当您需要正确更新模型时,请使用 save()

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().

这篇关于Django:save()vs update()更新数据库?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆