如何将django Model对象转换为包含所有字段的dict ?理想情况下,所有字段都包含外键和editable=False。
让我详细说明一下。假设我有一个django模型,如下所示:
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")
在终端中,我做了以下工作:
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()
我想把它转换成下面的字典:
{'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}
回答不满意的问题:
Django:将整个Model对象集转换为单个字典
如何将Django Model对象转换为字典,同时还保留外键?
@Zags的解决方案太棒了!
不过,为了使它对JSON友好,我要为datefields添加一个条件。
奖金轮
如果你想要一个更好的python命令行显示的django模型,让你的models子类如下:
from django.db import models
from django.db.models.fields.related import ManyToManyField
class PrintableModel(models.Model):
def __repr__(self):
return str(self.to_dict())
def to_dict(self):
opts = self._meta
data = {}
for f in opts.concrete_fields + opts.many_to_many:
if isinstance(f, ManyToManyField):
if self.pk is None:
data[f.name] = []
else:
data[f.name] = list(f.value_from_object(self).values_list('pk', flat=True))
elif isinstance(f, DateTimeField):
if f.value_from_object(self) is not None:
data[f.name] = f.value_from_object(self).timestamp()
else:
data[f.name] = None
else:
data[f.name] = f.value_from_object(self)
return data
class Meta:
abstract = True
例如,如果我们这样定义我们的模型:
class OtherModel(PrintableModel): pass
class SomeModel(PrintableModel):
value = models.IntegerField()
value2 = models.IntegerField(editable=False)
created = models.DateTimeField(auto_now_add=True)
reference1 = models.ForeignKey(OtherModel, related_name="ref1")
reference2 = models.ManyToManyField(OtherModel, related_name="ref2")
调用sommodel .objects.first()现在给出如下输出:
{'created': 1426552454.926738,
'value': 1, 'value2': 2, 'reference1': 1, u'id': 1, 'reference2': [1]}
当我试图使用django-rest框架将django站点转换为API时,我遇到了这个问题。通常django会从数据库中返回三种类型的对象。它们包括一个查询集、一个模型实例和一个分页器对象。对我来说,这些是需要转换的。
查询集
queryset就像django中的模型对象列表。这是把它转换成字典的代码。
model_data=Model.object.all()# This returns a queryset object
model_to_dict=[model for model in model_data.values()]
return Response(model_to_dict,status=status.HTTP_200_OK)
模型实例
模型实例是模型的单个对象。
model_instance=Model.objects.get(pk=1)# This will return only a single model object
model_to_dict=model_to_dict(model_instance)
return Response(model_to_dict,status=status.HTTP_200_OK)
Paginator对象
分页器对象是一个包含特定页面的模型对象的对象。
model_queryset=Model.objects.all()
paginator = Paginator(model_queryset, 10)
try:
selected_results = paginator.page(page)
except Exception:
selected_results=result
paginator_to_dict=list(selected_results.object_list.values())
return Response(selected_results,status=status.HTTP_200_OK)
至少我是这么解决的。
(不是故意的)
好吧,它并不依赖于类型。我可能误解了最初的问题,所以如果是这样的话请原谅我。如果你创建serliazers.py,那么你在里面创建了有元类的类。
Class MyModelSerializer(serializers.ModelSerializer):
class Meta:
model = modelName
fields =('csv','of','fields')
然后,当你在视图类中获得数据时,你可以:
model_data - Model.objects.filter(...)
serializer = MyModelSerializer(model_data, many=True)
return Response({'data': serilaizer.data}, status=status.HTTP_200_OK)
这就是我在很多地方所拥有的,它通过JSONRenderer返回漂亮的JSON。
正如我所说,这是由DjangoRestFramework提供的,所以值得研究一下。
你见过的最好的解决方案。
将django.db.models.Model实例和所有相关的ForeignKey, ManyToManyField和@Property函数字段转换为dict。
"""
Convert django.db.models.Model instance and all related ForeignKey, ManyToManyField and @property function fields into dict.
Usage:
class MyDjangoModel(... PrintableModel):
to_dict_fields = (...)
to_dict_exclude = (...)
...
a_dict = [inst.to_dict(fields=..., exclude=...) for inst in MyDjangoModel.objects.all()]
"""
import typing
import django.core.exceptions
import django.db.models
import django.forms.models
def get_decorators_dir(cls, exclude: typing.Optional[set]=None) -> set:
"""
Ref: https://stackoverflow.com/questions/4930414/how-can-i-introspect-properties-and-model-fields-in-django
:param exclude: set or None
:param cls:
:return: a set of decorators
"""
default_exclude = {"pk", "objects"}
if not exclude:
exclude = default_exclude
else:
exclude = exclude.union(default_exclude)
return set([name for name in dir(cls) if name not in exclude and isinstance(getattr(cls, name), property)])
class PrintableModel(django.db.models.Model):
class Meta:
abstract = True
def __repr__(self):
return str(self.to_dict())
def to_dict(self, fields: typing.Optional[typing.Iterable]=None, exclude: typing.Optional[typing.Iterable]=None):
opts = self._meta
data = {}
# support fields filters and excludes
if not fields:
fields = set()
else:
fields = set(fields)
default_fields = getattr(self, "to_dict_fields", set())
fields = fields.union(default_fields)
if not exclude:
exclude = set()
else:
exclude = set(exclude)
default_exclude = getattr(self, "to_dict_exclude", set())
exclude = exclude.union(default_exclude)
# support syntax "field__childField__..."
self_fields = set()
child_fields = dict()
if fields:
for i in fields:
splits = i.split("__")
if len(splits) == 1:
self_fields.add(splits[0])
else:
self_fields.add(splits[0])
field_name = splits[0]
child_fields.setdefault(field_name, set())
child_fields[field_name].add("__".join(splits[1:]))
self_exclude = set()
child_exclude = dict()
if exclude:
for i in exclude:
splits = i.split("__")
if len(splits) == 1:
self_exclude.add(splits[0])
else:
field_name = splits[0]
if field_name not in child_exclude:
child_exclude[field_name] = set()
child_exclude[field_name].add("__".join(splits[1:]))
for f in opts.concrete_fields + opts.many_to_many:
if self_fields and f.name not in self_fields:
continue
if self_exclude and f.name in self_exclude:
continue
if isinstance(f, django.db.models.ManyToManyField):
if self.pk is None:
data[f.name] = []
else:
result = []
m2m_inst = f.value_from_object(self)
for obj in m2m_inst:
if isinstance(PrintableModel, obj) and hasattr(obj, "to_dict"):
d = obj.to_dict(
fields=child_fields.get(f.name),
exclude=child_exclude.get(f.name),
)
else:
d = django.forms.models.model_to_dict(
obj,
fields=child_fields.get(f.name),
exclude=child_exclude.get(f.name)
)
result.append(d)
data[f.name] = result
elif isinstance(f, django.db.models.ForeignKey):
if self.pk is None:
data[f.name] = []
else:
data[f.name] = None
try:
foreign_inst = getattr(self, f.name)
except django.core.exceptions.ObjectDoesNotExist:
pass
else:
if isinstance(foreign_inst, PrintableModel) and hasattr(foreign_inst, "to_dict"):
data[f.name] = foreign_inst.to_dict(
fields=child_fields.get(f.name),
exclude=child_exclude.get(f.name)
)
elif foreign_inst is not None:
data[f.name] = django.forms.models.model_to_dict(
foreign_inst,
fields=child_fields.get(f.name),
exclude=child_exclude.get(f.name),
)
elif isinstance(f, (django.db.models.DateTimeField, django.db.models.DateField)):
v = f.value_from_object(self)
if v is not None:
data[f.name] = v.isoformat()
else:
data[f.name] = None
else:
data[f.name] = f.value_from_object(self)
# support @property decorator functions
decorator_names = get_decorators_dir(self.__class__)
for name in decorator_names:
if self_fields and name not in self_fields:
continue
if self_exclude and name in self_exclude:
continue
value = getattr(self, name)
if isinstance(value, PrintableModel) and hasattr(value, "to_dict"):
data[name] = value.to_dict(
fields=child_fields.get(name),
exclude=child_exclude.get(name)
)
elif hasattr(value, "_meta"):
# make sure it is a instance of django.db.models.fields.Field
data[name] = django.forms.models.model_to_dict(
value,
fields=child_fields.get(name),
exclude=child_exclude.get(name),
)
elif isinstance(value, (set, )):
data[name] = list(value)
else:
data[name] = value
return data
https://gist.github.com/shuge/f543dc2094a3183f69488df2bfb51a52
将模型转换为字典并保留所有的外键模型关系。我使用了以下方法:
无详细名称
from django.forms.models import model_to_dict
instance = MyModel.objects.get(pk=1) # EXAMPLE
instance_dict = {key: getattr(instance, key) for key in model_to_dict(instance).keys()}
输出
{'foreign_key': [<OtherModel: OtherModel object>],
'id': 1,
'many_to_many': [<OtherModel: OtherModel object>],
'normal_value': 1}
如果你想在模板中为外键关系显示__str__()值,这可能很有用。
将关键字参数fields=和exclude=包含到model_to_dict(instance,[…])中,使您可以过滤特定的字段。
详细名称
from django.forms.models import model_to_dict
instance = MyModel.objects.get(pk=1) # EXAMPLE
instance_dict = {instance._meta.get_field(key).verbose_name if hasattr(instance._meta.get_field(key), 'verbose_name') else key: getattr(instance, key) for key in model_to_dict(instance).keys()}
示例输出(如果给定示例有详细的名称)
{'Other Model:': [<OtherModel: OtherModel object>],
'id': 1,
'My Other Model:': [<OtherModel: OtherModel object>],
'Normal Value:': 1}