93

我有一个当前调用的函数Models.object.get(),它返回 0 或 1 个模型对象。如果它返回 0,我except DoesNotExist在函数的子句中创建一个新的模型实例。否则,我想更新现有实例中的字段,而不创建新实例。我最初试图调用.update()找到的实例,但.update()似乎只能在 QuerySets 上调用。如何绕过更改十几个字段,而无需调用.filter()和比较长度以了解我是否必须创建或更新预先存在的实例?

4

8 回答 8

106

随着 Django 1.7 的出现,现在有一个新的update_or_createQuerySet 方法,它应该完全符合您的要求。如果在数据库级别没有强制执行唯一性,请注意潜在的竞争条件。

文档中的示例:

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
于 2012-09-12T05:38:55.887 回答
53

如果您只想更新模型(如果存在)(不创建它):

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

mysql查询:

UPDATE `model` SET `field1` = 2 WHERE `model`.`id` = 223
于 2015-05-20T15:15:56.940 回答
43

从 Django 1.5 开始,模型保存上有一个 update_fields 属性。例如:

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

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

我更喜欢这种方法,因为如果您有多个 Web 应用程序实例更改模型实例的不同部分,它不会产生原子性问题。

于 2013-10-10T06:25:30.137 回答
25

我不知道这是好是坏,但是您可以尝试以下方法:

try:
    obj = Model.objects.get(id=some_id)
except Model.DoesNotExist:
    obj = Model.objects.create()
obj.__dict__.update(your_fields_dict) 
obj.save()
于 2012-09-12T05:49:22.350 回答
10

这是一个可以混合到任何模型类中的 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检查检查模型是否保存到数据库中,如果没有,则引发错误。

(注意:此方法适用于当您要更新模型并且您知道实例已保存到数据库中时,直接回答原始问题。白金 Azure 答案中update的内置方法已经涵盖了其他用例。 update_or_create)

你会像这样使用它(在将它混合到你的用户模型中之后):

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

除了拥有更好的 API 之外,这种方法的另一个优点是它调用了pre_saveandpost_save钩子,同时在另一个进程正在更新同一个模型时仍然避免原子性问题。

于 2016-10-16T22:58:54.067 回答
5

正如@Nils 提到的,您可以使用该方法的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

于 2018-10-12T09:17:59.867 回答
0

在这种情况下,我使用以下代码:

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

if not created:
   resp= "It was created"
else:
   resp= "OK"
   obj.save()
于 2012-09-12T07:28:17.333 回答
0

更新:

1 -单个实例: 获取实例并手动更新 get() 检索单个对象

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')
于 2021-11-15T12:14:32.520 回答