有很多方法可以将一个实例转换成字典,这些方法的处理边缘情况和接近期望结果程度不同。
1. instance.__dict__
instance.__dict__
返回 which
{'_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
的名称不正确,并且其中还有两个不需要的额外内容。
2. model_to_dict
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
的,但缺少不可编辑字段。
3. model_to_dict(..., 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
调用严格更糟糕。
4. query_set.values()
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
仍然缺失。
5. 自定义函数
Django的model_to_dict
代码已经包含了大部分答案。它明确删除了不可编辑的字段,因此删除该检查并获取多对多字段的外键ID将得到以下代码,其行为符合要求:
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)
正好可以给我们所需的结果:
{'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的ModelSerializer能够自动从模型中构建一个序列化器。
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是一个字符串而不是datetime对象。
额外福利回合:更好的模型打印
如果您想要一个在Python命令行中有更好显示效果的Django模型,请将您的模型作为以下模型的子类:
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
因此,例如,如果我们将我们的模型定义为:
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()
将会得到以下输出:
{'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}
to_dict
的方法,并按照你想要的方式处理它。 - karthikr