如何更新 django 模型实例的多个字段?
Posted
技术标签:
【中文标题】如何更新 django 模型实例的多个字段?【英文标题】:How to update multiple fields of a django model instance? 【发布时间】:2010-12-07 07:03:14 【问题描述】:我想知道,在 django 中更新模型实例的多个字段的标准方法是什么? ...如果我有一个包含某些字段的模型,
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 类问题,但我只是没有在文档中看到它。
【问题讨论】:
【参考方案1】:__dict__
很容易混淆,但这不适用于从父类继承的属性。
您可以遍历 dict 以分配给对象:
for (key, value) in my_data_dict.items():
setattr(obj, key, value)
obj.save()
或者您可以直接从查询集修改它(确保您的查询集只返回您感兴趣的对象):
FooModel.objects.filter(whatever="anything").update(**my_data_dict)
【讨论】:
谢谢@Wilfred。很有帮助。对于其他人:不要忘记在 for 循环之后执行obj.save()
请注意FooModel.objects.filter(whatever="anything").update(**my_data_dict)
会绕过保存方法。您最终可能会保存应该引发异常的东西。【参考方案2】:
你可以试试这个:
obj.__dict__.update(my_data_dict)
【讨论】:
这不适用于继承的属性。 它不适用于继承的属性意味着什么? 另外,您是否正在尝试使用 dict 更新 ForeignKey,相关值名称是field_name_id
而不是 field_name
,您需要小心。
这没有保留我的记录...我可能会丢失什么?
@tomascharad - 你必须像 obj.__dict__.update(my_data_dict)
然后 obj.save()
那样调用它来保存数据。【参考方案3】:
这似乎是您想要做的一件很自然的事情,但和您一样,我也没有在文档中找到它。文档确实说您应该在模型上对 save() 进行子类化。这就是我所做的。
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()
【讨论】:
考虑为模型添加一个新方法“dict_save”(因此模型的 2 个保存方法 - 普通和 dict)与主体在下次我需要这个时。我查看了我用来执行此操作的代码,除了我在保存之外执行此操作之外,它是相同的。有一个方法 update_model_obj_from_dict(model_object, update_dict) 与上面的主体几乎相同,并期望我会选择何时调用 save() 之后。我有点喜欢有选择。所以也许模型上有一个名为“set_from_dict”的方法,上面除了最后一行之外的所有内容,稍后再使用保存。【参考方案4】:我得到主键的名字,用它来过滤Queryset.filter()
并用Queryset.update()
更新。
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)
这让我可以更新一个实例,不管主键是什么。
【讨论】:
【参考方案5】:使用update()
更新
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)
【讨论】:
欢迎来到 SO。发布答案时,请附上您的代码说明,并记住格式化文本。 需要注意的是,这不会调用 save() 方法,也不会调用 pre_save/post_save 信号。 @Maxim 有没有办法手动触发这些信号,因为从未调用过save()
方法?
@enchance 您必须在每个实例上调用 save 方法,因为 update 方法不会调用它,也不会发送 pre/post 保存信号。 docs.djangoproject.com/en/3.0/ref/models/querysets/#update以上是关于如何更新 django 模型实例的多个字段?的主要内容,如果未能解决你的问题,请参考以下文章