如何在 Django ORM 上更新由 get()检索的单个模型实例?

我有一个函数,它目前调用 Models.object.get(),返回0或1个模型对象:

  • 如果返回0,则在函数的 except DoesNotExist子句中创建一个新的模型实例。
  • 否则,我将更新预先存在的 例如,没有创建一个新的。

我本来是想 在找到的实例上调用 .update(),但是 .update() 似乎只能在查询集上调用 更改十几个字段,而不调用 .filter()并进行比较 知道我是否需要创建或更新一个预先存在的 例子?

205782 次浏览

With the advent of Django 1.7, there is now a new update_or_create QuerySet method, which should do exactly what you want. Just be careful of potential race conditions if uniqueness is not enforced at the database level.

Example from the documentation:

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

The update_or_create method tries to fetch an object from database based on the given kwargs. If a match is found, it updates the fields passed in the defaults dictionary.


Pre-Django 1.7:

Change the model field values as appropriate, then call .save() to persist the changes:

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

I don't know how good or bad this is, but you can try something like this:

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

I am using the following code in such cases:

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


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

As of Django 1.5, there is an update_fields property on model save. eg:

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

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

I prefer this approach because it doesn't create an atomicity problem if you have multiple web app instances changing different parts of a model instance.

if you want only to update model if exist (without create it):

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

mysql query:

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

Here's a mixin that you can mix into any model class which gives each instance an update method:

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

The self._state.adding check checks to see if the model is saved to the database, and if not, raises an error.

(Note: This update method is for when you want to update a model and you know the instance is already saved to the database, directly answering the original question. The built-in update_or_create method featured in Platinum Azure's answer already covers the other use-case.)

You would use it like this (after mixing this into your user model):

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

Besides having a nicer API, another advantage to this approach is that it calls the pre_save and post_save hooks, while still avoiding atomicity issues if another process is updating the same model.

As @Nils mentionned, you can use the update_fields keyword argument of the save() method to manually specify the fields to update.

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


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

The update_fields value should be a list of the fields to update as strings.

See https://docs.djangoproject.com/en/2.1/ref/models/instances/#specifying-which-fields-to-save

update:

1 - individual instance : get instance and update manually get() retrieve individual object

post = Post.objects.get(id=1)
post.title = "update title"
post.save()

2 - Set of instances : use update() method that works only with queryset that what would be returned by filter() method

Post.objects.filter(author='ahmed').update(title='updated title for ahmed')