Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/django/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python Django:对由.get()检索的单个模型实例调用.update()?_Python_Django_Models - Fatal编程技术网

Python Django:对由.get()检索的单个模型实例调用.update()?

Python Django:对由.get()检索的单个模型实例调用.update()?,python,django,models,Python,Django,Models,我有一个函数,当前调用Models.object.get(),它返回0或1个模型对象。如果它返回0,我将在函数的子句中创建一个新的模型实例,DoesNotExist除外。否则,我希望更新预先存在的实例中的字段,而不创建新实例。我最初试图在找到的实例上调用.update(),但是.update()似乎只能在查询集上调用。我如何在不调用.filter()和比较长度的情况下更改十几个字段以了解是否必须创建或更新预先存在的实例?随着Django 1.7的出现,现在有了一个新的QuerySet方法,它应该

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

随着Django 1.7的出现,现在有了一个新的QuerySet方法,它应该完全满足您的需要。如果不在数据库级别强制唯一性,请小心潜在的竞争条件

文档中的示例:

obj, created = Person.objects.update_or_create(
    first_name='John', last_name='Lennon',
    defaults={'first_name': 'Bob'},
)
update\u或\u create
方法尝试从数据库中获取对象 基于给定的kwargs。如果找到匹配项,它将更新 在
默认值中传递的字段


前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

我不知道这是好是坏,但你可以试试这样:

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

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

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

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

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

obj.save(更新字段=['field1','field2',…])


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

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

mysql查询:

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

这里有一个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.\u状态。添加
检查是否将模型保存到数据库中,如果未保存,则会引发错误

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

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


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

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

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\u fields
值应该是要更新为字符串的字段列表


请参见

首先可以使用get\u或\u create,然后可以显示一些代码……但是假设我有20个字段,有没有更简单的方法来更新它们?使用.update()我想我可以传入**kwargs?试着看看这里:这种方法有原子性问题——如果两个应用程序实例都更改了数据库中的同一个实例,那么其中一个可能会破坏另一个。也只有在处理对象时才使用这种方法。如果您只想更新,最好使用带有相应pk属性的过滤器。这样做的优点是只发出一个查询。如果您使用get进行更新,将使用两个查询。@zhuyxn
用于kwargs.iteritems()中的attr,val:setattr(obj,attr,val)
他要求使用.get()而不是.filter()updated\u字段是列表而不是字典,那么我们将如何传递字段的更新值?@brainLoop,您不会单独传递这些值。您可以在对象本身上设置它们。obj.field1=在obj.update_fields参数上调用save之前的值通过强制更新指定字段的模型来防止竞争条件。通过这种方式,我们避免将模型加载到内存中然后保存,这意味着即使存在另一个应用程序实例,它也无法在这两者之间执行任何操作。异常是繁重的操作,不推荐使用异常是合理和正确的。注意:这个答案中的create()应该是create(id=some_id),并有自己的try/except块来处理重复的密钥和/或竞争条件,在重试机制中运行,等等。
user = request.user
user.update(favorite_food="ramen")
obj_instance = Model.objects.get(field=value)
obj_instance.field = new_value
obj_instance.field2 = new_value2

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