[英]How do I use a dictionary to update fields in Django models?
假设我有一个这样的模型:
class Book(models.Model):
num_pages = ...
author = ...
date = ...
我可以创建一个字典,然后使用它插入或更新模型吗?
d = {"num_pages":40, author:"Jack", date:"3324"}
这是使用字典 d 创建的示例:
Book.objects.create(**d)
要更新现有模型,您需要使用 QuerySet filter
方法。 假设您知道要更新的 Book 的pk
:
Book.objects.filter(pk=pk).update(**d)
如果您知道要创建它:
Book.objects.create(**d)
假设您需要检查现有实例,您可以使用 get 或 create 找到它:
instance, created = Book.objects.get_or_create(slug=slug, defaults=d)
if not created:
for attr, value in d.items():
setattr(instance, attr, value)
instance.save()
正如另一个答案中提到的,您也可以使用查询集管理器上的update
功能,但我相信这不会发出任何信号(如果您不使用它们,这对您来说可能无关紧要)。 但是,您可能不应该使用它来更改单个对象:
Book.objects.filter(id=id).update()
使用**
创建新模型。 遍历字典并使用setattr()
来更新现有模型。
来自 Tom Christie 的 Django Rest Framework
https://github.com/tomchristie/django-rest-framework/blob/master/rest_framework/serializers.py
for attr, value in validated_data.items():
setattr(instance, attr, value)
instance.save()
如果您已经有 Django 对象并且想要更新它的字段,则可以不使用过滤器进行更新。 因为您已经拥有它,在这种情况下,您可能会:
your_obj.__dict__.update(your_dict)
your_obj.save()
除了其他答案之外,这里还有一个更安全的版本,以防止混淆相关字段:
def is_simple_editable_field(field):
return (
field.editable
and not field.primary_key
and not isinstance(field, (ForeignObjectRel, RelatedField))
)
def update_from_dict(instance, attrs, commit):
allowed_field_names = {
f.name for f in instance._meta.get_fields()
if is_simple_editable_field(f)
}
for attr, val in attrs.items():
if attr in allowed_field_names:
setattr(instance, attr, val)
if commit:
instance.save()
它会检查您尝试更新的字段是否可编辑、不是主键且不是相关字段之一。
用法示例:
book = Book.objects.first()
update_from_dict(book, {"num_pages":40, author:"Jack", date:"3324"})
豪华的 DRF 序列化程序.create
和.update
方法具有有限且经过验证的字段集,手动更新不是这种情况。
要更新一条记录,您可以使用非常方便的功能:
class Book(models.Model):
num_pages = ...
author = ...
date = ...
def update(self,*args, **kwargs):
for name,values in kwargs.items():
try:
setattr(self,name,values)
except KeyError:
pass
self.save()
进而:
d = {"num_pages":40, author:"Jack", date:"3324"}
book = Book.objects.first()
book.update(**d)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.