python-Django:在由.get()检索的单个模型实例上调用.update()?

我有一个当前调用Models.object.get()的函数,该函数返回0或1个模型对象。 如果返回0,则在该函数的2768791283866066010625子句中创建一个新的模型实例。 否则,我想在不创建新实例的情况下更新现有实例中的字段。 我最初试图在找到的实例上调用.update(),但是.update()似乎只能在QuerySet上调用。 我如何绕过十几个字段而不调用.filter()并比较长度来知道是否必须创建或更新现有实例?

zhuyxn asked 2020-02-29T10:02:07Z
7个解决方案
58 votes

随着Django 1.7的到来,现在有了一个新的.save() QuerySet方法,该方法可以完全满足您的要求。 如果在数据库级别未强制唯一性,请小心潜在的竞争条件。

文档中的示例:

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

.save()方法尝试从数据库中获取对象   根据给定的wargs。 如果找到匹配项,它将更新   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
Platinum Azure answered 2020-02-29T10:02:43Z
35 votes

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

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

[HTTPS://docs.Django project.com/恩/Dev/热风/models/instances/]

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

Nils answered 2020-02-29T10:03:16Z
26 votes

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

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

mysql查询:

UPDATE `model` SET `field1` = 2 WHERE `model`.`id` = 223
Eyal Ch answered 2020-02-29T10:03:40Z
20 votes

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

try:
    obj = Model.objects.get(id=some_id)
except Model.DoesNotExist:
    obj = Model.objects.create()
obj.__dict__.update(your_fields_dict) 
obj.save()
Rohan answered 2020-02-29T10:04:00Z
7 votes

这是一个mixin,您可以将其混合到任何模型类中,该模型类为每个实例提供pre_save方法:

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

pre_save检查检查是否将模型保存到数据库,如果没有保存,则会引发错误。

(注意:此pre_save方法适用于要更新模型的情况,并且您知道实例已保存到数据库中,可以直接回答原始问题。PlatinumAzure答案中的内置post_save方法已涵盖其他用途- 案件。)

您可以这样使用它(将其混合到用户模型中之后):

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

除了拥有更好的API外,此方法的另一个优点是它调用了pre_savepost_save钩子,而如果另一个进程正在更新同一模型,则仍然避免了原子性问题。

Julien answered 2020-02-29T10:04:38Z
0 votes

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

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

if not created:
   resp= "It was created"
else:
   resp= "OK"
   obj.save()
Aragon answered 2020-02-29T10:04:58Z
0 votes

如@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值应该是要更新为字符串的字段列表。

参见[https://docs.djangoproject.com/zh-CN/2.1/ref/models/instances/#specifying-which-fields-to-save]

Rémi Héneault answered 2020-02-29T10:05:27Z
translate from https://stackoverflow.com:/questions/12381756/django-calling-update-on-a-single-model-instance-retrieved-by-get