我有一个函数,目前调用了Models.object.get()
,该函数返回0或1个模型对象:
- 如果它返回0,在函数的
except DoesNotExist
子句中,我将创建一个新的模型实例。 - 否则,我想更新预先存在的实例中的字段,而不创建新的实例。
最初我试图在找到的实例上调用.update()
,但是.update()
似乎只能在QuerySets上调用。如何避免更改一打字段,而不使用.filter()
并比较长度以知道是否必须创建或更新预先存在的实例?
我有一个函数,目前调用了Models.object.get()
,该函数返回0或1个模型对象:
except DoesNotExist
子句中,我将创建一个新的模型实例。最初我试图在找到的实例上调用.update()
,但是.update()
似乎只能在QuerySets上调用。如何避免更改一打字段,而不使用.filter()
并比较长度以知道是否必须创建或更新预先存在的实例?
随着Django 1.7的到来,现在有一个新的update_or_create
QuerySet方法,它应该可以完全满足你的需求。只是要注意,如果不在数据库级别上强制执行唯一性,则可能会存在潜在的竞态条件。
文档中的示例:
obj, created = Person.objects.update_or_create(
first_name='John', last_name='Lennon',
defaults={'first_name': 'Bob'},
)
update_or_create
方法基于给定的 kwargs 尝试从数据库获取一个对象。如果找到匹配项,则更新defaults
字典中传递的字段。
Django 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
对于kwargs中的每个属性和值,使用setattr函数将其设置到obj对象中。
- DylanYoung.update_or_create()
在底层也使用了 .save()
,因此如果对象已存在,则最终效果相同,这可能是您想要避免的。 - slajma如果你只想在模型已存在的情况下更新它(而不创建新模型):
Model.objects.filter(id = 223).update(field1 = 2)
MySQL 查询:
UPDATE `model` SET `field1` = 2 WHERE `model`.`id` = 223
.first()
,因为.filter()
应该使用唯一的ID作为参数。 - Dwi Mulia Mokogintaobject has no attribute 'update'
的错误信息。 - AlxVallejo从Django 1.5开始,模型保存时有一个update_fields属性。例如:
obj.save(update_fields=['field1', 'field2', ...])
https://docs.djangoproject.com/en/dev/ref/models/instances/
我喜欢这种方法,因为如果您有多个Web应用程序实例更改模型实例的不同部分,则不会创建原子性问题。
我不知道这个方法好坏如何,但你可以尝试这样做:
try:
obj = Model.objects.get(id=some_id)
except Model.DoesNotExist:
obj = Model.objects.create()
obj.__dict__.update(your_fields_dict)
obj.save()
这是一个 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
方法是用于更新已知实例已保存到数据库中的模型时使用,直接回答原始问题。在Platinum Azure的回答中特色的内置update_or_create
方法已经涵盖了其他用例。)
您可以像这样使用它(在将其混合到用户模型后):
user = request.user
user.update(favorite_food="ramen")
除了具有更好的 API 之外,这种方法的另一个优点是它调用了 pre_save
和 post_save
钩子,同时仍然避免了如果另一个进程正在更新相同模型时的原子性问题。
正如@Nils所提到的,您可以使用save()
方法的update_fields
关键字参数来手动指定要更新的字段。
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
值应该是一个字符串列表,表示要更新的字段。post = Post.objects.get(id=1)
post.title = "update title"
post.save()
2 - 实例集合: 使用update()方法,该方法仅适用于由filter()方法返回的查询集。
Post.objects.filter(author='ahmed').update(title='updated title for ahmed')
我在这种情况下使用以下代码:
obj, created = Model.objects.get_or_create(id=some_id)
if not created:
resp= "It was created"
else:
resp= "OK"
obj.save()