Подтвердить что ты не робот

Django: save() vs update() для обновления базы данных?

Я пишу приложение Django, и мне нужна функция для обновления поля в базе данных. Есть ли какая-нибудь причина, чтобы сделать один из этих методов, а не другой?

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)

Кажется, что второй лучше, потому что он делает это в одном вызове БД вместо двух. Есть ли причина, почему выборка, а затем обновление лучше?

4b9b3361

Ответ 1

Существует несколько ключевых отличий.

update используется для набора запросов, поэтому можно одновременно обновлять сразу несколько объектов.

Как отмечалось в @FallenAngel, существуют различия в том, как настраивается метод save(), но также важно иметь в виду signals и ModelManagers. Я создал небольшое тестовое приложение, чтобы показать некоторые ценные различия. Я использую Python 2.7.5, Django == 1.7.7 и SQLite, обратите внимание, что окончательные SQL могут различаться в разных версиях Django и разных машинах баз данных.

Хорошо, вот пример кода.

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-запросах:

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

Далее, давайте поговорим об переопределении метода save(). Он вызывается только один раз для метода save(). Стоит отметить, что .objects.create() также вызывает метод save().

Но update() не называет save() на моделях. И если для update() вызывается метод save(), поэтому сигналы также не запускаются. Выход:

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() только один раз.

Разрешение. Если вам нужно "тихо" обновить свои значения, без вызова save() - используйте update. Usecases: last_seen поле пользователя. Когда вам нужно правильно обновить свою модель, используйте save().

Ответ 2

Оба выглядят одинаково, но есть несколько ключевых моментов:

  • save() приведет к запуску любого переопределенного метода Model.save(), но update() не будет запускать это и сделать прямое обновление на уровне базы данных. Поэтому, если у вас есть некоторые модели с переопределенными методами сохранения, вы должны либо не использовать обновление, либо найти другой способ сделать то, что вы делаете над этими переопределенными методами save().

  • obj.save() может иметь некоторые побочные эффекты, если вы не будете осторожны. Вы извлекаете объект с помощью get(...), и все значения полей модели передаются в ваш объект. Когда вы вызываете obj.save(), django сохранит текущее состояние объекта для записи. Поэтому, если некоторые изменения происходят между get() и save() каким-либо другим процессом, эти изменения будут потеряны. используйте save(update_fields=[.....]) для устранения таких проблем.

  • До Django версии 1.5 Django выполнял SELECT до INSERT/UPDATE, поэтому он стоит 2 выполнения запроса. С версией 1.5 этот метод устарел.

Здесь, есть хороший метод руководства или save() и update() и как они выполняются.

Ответ 3

Метод

save() может использоваться для вставки новой записи и обновления существующей записи и обычно используется для сохранения экземпляра отдельной записи (строки в mysql) в базе данных.

update() не используется для вставки записей и может использоваться для обновления нескольких записей (строк в mysql) в базе данных.

Ответ 4

Обновление даст вам лучшую производительность с набором запросов более чем одного объекта, так как это сделает один вызов базы данных на каждый запрос.

Однако сохранение полезно, так как легко переопределить метод сохранения в вашей модели и добавить туда дополнительную логику. Например, в моем приложении я обновляю даты, когда меняются другие поля.

Class myModel(models.Model): 
    name = models.CharField()
    date_created = models.DateField()

    def save(self):
        if not self.pk :
           ### we have a newly created object, as the db id is not set
           self.date_created = datetime.datetime.now()
        super(myModel , self).save()

Ответ 5

Обновление работает только при обновлении запросов. Если вы хотите обновить несколько полей одновременно, скажем, из dict для одного экземпляра объекта, вы можете сделать что-то вроде:

obj.__dict__.update(your_dict)
obj.save()

Имейте в виду, что ваш словарь должен содержать правильное отображение, где ключи должны быть вашими именами полей и значениями, которые вы хотите вставить.