问题描述
如何将 django 模型对象转换为具有 所有 字段的字典?理想情况下,所有内容都包括外键和具有可编辑=False 的字段.
How does one convert a django Model object to a dict with all of its fields? All ideally includes foreign keys and fields with editable=False.
让我详细说明.假设我有一个 django 模型,如下所示:
Let me elaborate. Let's say I have a django model like the following:
from django.db import models
class OtherModel(models.Model): pass
class SomeModel(models.Model):
normal_value = models.IntegerField()
readonly_value = models.IntegerField(editable=False)
auto_now_add = models.DateTimeField(auto_now_add=True)
foreign_key = models.ForeignKey(OtherModel, related_name="ref1")
many_to_many = models.ManyToManyField(OtherModel, related_name="ref2")
在终端中,我做了以下事情:
In the terminal, I have done the following:
other_model = OtherModel()
other_model.save()
instance = SomeModel()
instance.normal_value = 1
instance.readonly_value = 2
instance.foreign_key = other_model
instance.save()
instance.many_to_many.add(other_model)
instance.save()
我想把它转换成下面的字典:
I want to convert this to the following dictionary:
{'auto_now_add': datetime.datetime(2015, 3, 16, 21, 34, 14, 926738, tzinfo=<UTC>),
'foreign_key': 1,
'id': 1,
'many_to_many': [1],
'normal_value': 1,
'readonly_value': 2}
回答不满意的问题:
Questions with unsatisfactory answers:
Django:转换整个模型的对象集合到一个字典中
如何将 Django 模型对象转换为字典并且仍然拥有它们的外键?
推荐答案
有很多方法可以将实例转换为字典,不同程度的极端情况处理和接近所需结果.
There are many ways to convert an instance to a dictionary, with varying degrees of corner case handling and closeness to the desired result.
instance.__dict__
返回
{'_foreign_key_cache': <OtherModel: OtherModel object>,
'_state': <django.db.models.base.ModelState at 0x7ff0993f6908>,
'auto_now_add': datetime.datetime(2018, 12, 20, 21, 34, 29, 494827, tzinfo=<UTC>),
'foreign_key_id': 2,
'id': 1,
'normal_value': 1,
'readonly_value': 2}
这是迄今为止最简单的,但缺少 many_to_many
,foreign_key
名称错误,其中包含两个不需要的额外内容.
This is by far the simplest, but is missing many_to_many
, foreign_key
is misnamed, and it has two unwanted extra things in it.
from django.forms.models import model_to_dict
model_to_dict(instance)
返回
{'foreign_key': 2,
'id': 1,
'many_to_many': [<OtherModel: OtherModel object>],
'normal_value': 1}
这是唯一一个有 many_to_many
的,但缺少不可编辑的字段.
This is the only one with many_to_many
, but is missing the uneditable fields.
from django.forms.models import model_to_dict
model_to_dict(instance, fields=[field.name for field in instance._meta.fields])
返回
{'foreign_key': 2, 'id': 1, 'normal_value': 1}
这比标准的 model_to_dict
调用更糟糕.
This is strictly worse than the standard model_to_dict
invocation.
SomeModel.objects.filter(id=instance.id).values()[0]
返回
{'auto_now_add': datetime.datetime(2018, 12, 20, 21, 34, 29, 494827, tzinfo=<UTC>),
'foreign_key_id': 2,
'id': 1,
'normal_value': 1,
'readonly_value': 2}
这与 instance.__dict__
的输出相同,但没有额外的字段.foreign_key_id
仍然错误,many_to_many
仍然缺失.
This is the same output as instance.__dict__
but without the extra fields.
foreign_key_id
is still wrong and many_to_many
is still missing.
django 的 model_to_dict
的代码给出了大部分答案.它显式删除了不可编辑的字段,因此删除该检查并获取多对多字段的外键 id 会导致以下代码按预期运行:
The code for django's model_to_dict
had most of the answer. It explicitly removed non-editable fields, so removing that check and getting the ids of foreign keys for many to many fields results in the following code which behaves as desired:
from itertools import chain
def to_dict(instance):
opts = instance._meta
data = {}
for f in chain(opts.concrete_fields, opts.private_fields):
data[f.name] = f.value_from_object(instance)
for f in opts.many_to_many:
data[f.name] = [i.id for i in f.value_from_object(instance)]
return data
虽然这是最复杂的选项,但调用 to_dict(instance)
可以为我们提供准确的结果:
While this is the most complicated option, calling to_dict(instance)
gives us exactly the desired result:
{'auto_now_add': datetime.datetime(2018, 12, 20, 21, 34, 29, 494827, tzinfo=<UTC>),
'foreign_key': 2,
'id': 1,
'many_to_many': [2],
'normal_value': 1,
'readonly_value': 2}
<小时>
6.使用序列化器
Django Rest Framework 的 ModelSerialzer 允许您从模型自动构建序列化程序.
6. Use Serializers
Django Rest Framework's ModelSerialzer allows you to build a serializer automatically from a model.
from rest_framework import serializers
class SomeModelSerializer(serializers.ModelSerializer):
class Meta:
model = SomeModel
fields = "__all__"
SomeModelSerializer(instance).data
返回
{'auto_now_add': '2018-12-20T21:34:29.494827Z',
'foreign_key': 2,
'id': 1,
'many_to_many': [2],
'normal_value': 1,
'readonly_value': 2}
这几乎和自定义函数一样好,但是 auto_now_add 是一个字符串而不是一个日期时间对象.
This is almost as good as the custom function, but auto_now_add is a string instead of a datetime object.
如果你想要一个有更好的 python 命令行显示的 django 模型,让你的模型子类如下:
If you want a django model that has a better python command-line display, have your models child-class the following:
from django.db import models
from itertools import chain
class PrintableModel(models.Model):
def __repr__(self):
return str(self.to_dict())
def to_dict(instance):
opts = instance._meta
data = {}
for f in chain(opts.concrete_fields, opts.private_fields):
data[f.name] = f.value_from_object(instance)
for f in opts.many_to_many:
data[f.name] = [i.id for i in f.value_from_object(instance)]
return data
class Meta:
abstract = True
例如,如果我们这样定义模型:
So, for example, if we define our models as such:
class OtherModel(PrintableModel): pass
class SomeModel(PrintableModel):
normal_value = models.IntegerField()
readonly_value = models.IntegerField(editable=False)
auto_now_add = models.DateTimeField(auto_now_add=True)
foreign_key = models.ForeignKey(OtherModel, related_name="ref1")
many_to_many = models.ManyToManyField(OtherModel, related_name="ref2")
调用 SomeModel.objects.first()
现在会给出如下输出:
Calling SomeModel.objects.first()
now gives output like this:
{'auto_now_add': datetime.datetime(2018, 12, 20, 21, 34, 29, 494827, tzinfo=<UTC>),
'foreign_key': 2,
'id': 1,
'many_to_many': [2],
'normal_value': 1,
'readonly_value': 2}
这篇关于将 Django 模型对象转换为 dict 并且所有字段都完好无损的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!