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