如何更新django模型实例的多个字段?

How to update multiple fields of a django model instance?

我想知道,在Django更新模型实例的多个字段的标准方法是什么?…如果我有一些领域的模型,

1
2
3
4
5
Class foomodel(models.Model):
    field1 = models.CharField(max_length=10)
    field2 = models.CharField(max_length=10)
    field3 = models.CharField(max_length=10)
    ...

…我用给定的一个字段实例化它,然后在一个单独的步骤中,我想提供其余的字段,如何通过传递字典或键值参数来实现这一点呢?可能吗?

换言之,假设我有一个字典,其中包含一些数据,其中包含我想要写入该模型实例的所有内容。模型实例已在单独的步骤中实例化,我们假设它尚未持久化。我可以对每个字段说foo_instance.field1 = my_data_dict['field1'],但有一点告诉我应该有一种方法可以在模型实例上调用一个方法,我只需一次传递所有字段-值对,它就会更新它们。有点像foo_instance.update(my_data_dict)。我看不到像这样的内置方法,我是不是缺少了它,或者如何有效地完成这项工作?

我觉得这是一个很明显的RTM问题,但我在医生那里没有看到。


很容易与__dict__混淆,但这不适用于从父类继承的属性。

您可以循环访问要分配给对象的dict:

1
2
for (key, value) in my_data_dict.items():
    setattr(obj, key, value)

或者您可以直接从查询集修改它(确保您的查询集只返回您感兴趣的对象):

1
FooModel.objects.filter(whatever="anything").update(**my_data_dict)


你可以试试这个:

1
obj.__dict__.update(my_data_dict)


这似乎是一件很自然的事情,你想做,但像你一样,我也没有在医生那里找到它。文档确实指出应该在模型上使用子类save()。我就是这么做的。

1
2
3
4
5
def save(self, **kwargs):
    mfields = iter(self._meta.fields)
    mods = [(f.attname, kwargs[f.attname]) for f in mfields if f.attname in kwargs]
    for fname, fval in mods: setattr(self, fname, fval)
    super(MyModel, self).save()


我得到了主键的名称,用它过滤Queryset.filter(),用Queryset.update()更新。

1
2
3
4
5
6
7
8
fooinstance = ...    
# Find primary key and make a dict for filter
pk_name foomodel._meta.pk.name
filtr = {pk_name: getattr(fooinstance, pk_name)}
# Create a dict attribute to update
updat = {'name': 'foo', 'lastname': 'bar'}
# Apply
foomodel.objects.filter(**filtr).update(**updat)

这允许我更新一个实例,不管主键是什么。


使用update()更新

1
2
3
4
Discussion.objects.filter(slug=d.slug)
    .update(title=form_data['title'],
            category=get_object_or_404(Category, pk=form_data['category']),
            description=form_data['description'], closed=True)