Django: Вызов.update() для экземпляра одной модели, полученного с помощью.get()?

У меня есть функция, которая в настоящее время вызывает Models.object.get(), которая возвращает либо 0, либо 1 объект модели. Если он возвращает 0, я создаю экземпляр новой модели в except DoesNotExist предложения, except DoesNotExist от except DoesNotExist. В противном случае я хотел бы обновить поля в уже существующем экземпляре, не создавая новый. Первоначально я пытался вызвать .update() в экземпляре, который был найден, но .update() кажется, только вызываемый на QuerySets. Как мне обойти изменение дюжины полей, не вызывая .filter() и сравнивая длины, чтобы знать, нужно ли мне создавать или обновлять ранее существовавший экземпляр?

Ответ 1

С появлением Django 1.7 появился новый update_or_create QuerySet update_or_create, который должен делать именно то, что вы хотите. Просто будьте осторожны с возможными условиями гонки, если уникальность не обеспечивается на уровне базы данных.

Пример из документации:

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

Метод update_or_create пытается извлечь объект из базы данных на основе заданных kwargs. Если совпадение найдено, оно обновляет поля, переданные в словаре по defaults.


Пре-Джанго 1.7:

Измените значения поля модели соответствующим образом, затем вызовите .save() чтобы сохранить изменения:

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

Ответ 2

Начиная с Django 1.5 существует свойство update_fields для сохранения модели. например:

obj.save(update_fields=['field1', 'field2',...])

https://docs.djangoproject.com/en/dev/ref/models/instances/

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

Ответ 3

если вы хотите только обновить модель, если она существует (без ее создания):

Model.objects.filter(id = 223).update(field1 = 2)

mysql query:

UPDATE 'model' SET 'field1' = 2 WHERE 'model'.'id' = 223

Ответ 4

Я не знаю, насколько это хорошо или плохо, но вы можете попробовать что-то вроде этого:

try:
    obj = Model.objects.get(id=some_id)
except Model.DoesNotExist:
    obj = Model.objects.create()
obj.__dict__.update(your_fields_dict) 
obj.save()

Ответ 5

Здесь mixin, который вы можете смешивать в любой класс модели, который дает каждому экземпляру метод update:

class UpdateMixin(object):
    def update(self, **kwargs):
        if self._state.adding:
            raise self.DoesNotExist
        for field, value in kwargs.items():
            setattr(self, field, value)
        self.save(update_fields=kwargs.keys())

Проверка self._state.adding проверяет, сохраняется ли модель в базе данных, а если нет, возникает ошибка.

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

Вы бы использовали его так (после его смешивания с моделью пользователя):

user = request.user
user.update(favorite_food="ramen")

Помимо более удобного API, еще одним преимуществом этого подхода является то, что он вызывает pre_save и post_save, но при этом все еще избегает проблем с атомарностью, если другой процесс обновляет ту же модель.

Ответ 6

В таких случаях я использую следующий код:

obj, created = Model.objects.get_or_create(id=some_id)

if not created:
   resp= "It was created"
else:
   resp= "OK"
   obj.save()

Ответ 7

Как упоминалось в @Nils, вы можете использовать update_fields ключевого слова update_fields метода save() чтобы вручную указать поля для обновления.

obj_instance = Model.objects.get(field=value)
obj_instance.field = new_value
obj_instance.field2 = new_value2

obj_instance.save(update_fields=['field', 'field2'])

Значение update_fields должно быть списком полей, которые нужно обновить как строки.

См. Https://docs.djangoproject.com/en/2.1/ref/models/instances/#specifying-which-fields-to-save.