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

zhu*_*yxn 50 python django models

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

Pla*_*ure 60

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

文档中的示例:

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

Pre-Django 1.7:

根据需要更改模型字段值,然后调用update_or_create以保留更改:

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
Run Code Online (Sandbox Code Playgroud)

  • 但是假设我有 20 个字段,有没有更简单的方法来更新它们?使用 .update() 我想我可以传入 **kwargs? (4认同)
  • 这种方法存在原子性问题 - 如果两个应用实例都改变了DB中的相同实例,则可能会破坏另一个实例. (4认同)

Nil*_*ils 36

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

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

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

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

  • @brainLoop,您不会单独传递这些值。您可以将它们设置在对象本身上。obj.field1=在 obj 上调用 save 之前的值。 (2认同)

Eya*_* Ch 26

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

Model.objects.filter(id = 223).update(field1 = 2)
Run Code Online (Sandbox Code Playgroud)

mysql查询:

UPDATE `model` SET `field1` = 2 WHERE `model`.`id` = 223
Run Code Online (Sandbox Code Playgroud)

  • 他要求使用 .get() 特别不是 .filter() (4认同)

Roh*_*han 20

我不知道这有多好或多坏,但你可以尝试这样的事情:

try:
    obj = Model.objects.get(id=some_id)
except Model.DoesNotExist:
    obj = Model.objects.create()
obj.__dict__.update(your_fields_dict) 
obj.save()
Run Code Online (Sandbox Code Playgroud)

  • 例外是合理且正确的。注意:这个答案中的 create() 应该是 create(id=some_id) ,并且有自己的 try/ except 块来处理重复的键和/或竞争条件,在重试机制中运行等。 (3认同)
  • 例外是Python方式,并不重,推荐使用。 (3认同)
  • 繁重操作除外,不推荐 (2认同)

Jul*_*ien 7

这是一个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())
Run Code Online (Sandbox Code Playgroud)

self._state.adding检查检查,看是否该模型被保存到数据库中,如果没有,会产生错误.

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

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

user = request.user
user.update(favorite_food="ramen")
Run Code Online (Sandbox Code Playgroud)

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


Rém*_*ult 5

正如@Nils 提到的,您可以使用update_fieldssave()方法的关键字参数来手动指定要更新的字段。

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

obj_instance.save(update_fields=['field', 'field2'])
Run Code Online (Sandbox Code Playgroud)

update_fields值应该是要更新为字符串的字段列表。

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