为什么不能像这样更新 Django 模型实例:instance(**update_dict)?

Why is it not possible to update a django model instance like this: instance(**update_dict)?

我可以用 Model(**dictionary) 创建一个新的 django 模型对象,但是如果我想以同样的方式更新一个实例,我发现只有 update_or_create 有问题并且经常 returns 'duplicate PK' 错误。在模型对象上调用自定义辅助函数似乎也不是特别 pythonic。或者,您可以使用此模式:

 Model.objects.get(id=id).update(**dict)

model.__dict__.update(**dict)
model.save()

后者感觉像是一个 hack,我读过几次它不是 'supposed' 以这种方式完成的。第一种方法需要查询调用,但又感觉不正确,因为模型实例可能已经实例化,要更新它,我们需要再次向数据库发送查询吗?

我也读到 'you can do this with a form' - 但并不总是用户在数据库中更新模型,我们可能会编写各种需要更新模型的函数。我想知道,下面的代码不是 possible/implemented 是不是有原因?模型对象不能以这种方式直接调用和更新是有原因的吗?

model_instance(**dict)
model_instance.save()

没有内置的东西可以通过输入关键字参数来更新模型实例中的字段值。

以下查询将立即更新数据库行,并且有一个额外的缺点,即它不会调用您可能已注册到模型的任何预保存或 post-保存信号:

Model.objects.get(id=id).update(**dict)

为什么这不起作用:

model_instance(**dict)

实例对象通常不可调用。 Class 对象(实例化实例对象)并且传递给它们的可调用对象的 kwargs 在它们的 __init__ 方法中进行评估。例如,当您创建字典 mydict = dict() 时,您无法通过调用 mydict(**kwargs).

来更新它

不过您可以创建自己的模型方法。例如,您可以创建一个 abstract base class,您的所有模型都继承自(而不是 models.Model),例如

class ModelWithUpdate(models.Model):

    class Meta:
        abstract = True

    def update(self, commit=False, **kwargs):
        for key, value in kwargs.items():
            setattr(self, key, value)
        if commit:
            self.save()

然后你的用法是:

model_instance.update(**dict)
model_instance.save()

# or a shortcut
model_instance.update(commit=True, **dict)

刚刚:

Model.objects.filter(id=id).update(**kwargs)