将Django模型对象转换为所有字段不变的字典

如何将django模型对象转换为所有字段的字典? 所有理想情况下都包含带有editable = False的外键和字段。

让我详细说一下。 假设我有如下的django模型:

from django.db import models class OtherModel(models.Model): pass class SomeModel(models.Model): 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") 

在terminal,我做了以下几点:

 other_model = OtherModel() other_model.save() instance = SomeModel() instance.value = 1 instance.value2 = 2 instance.reference1 = other_model instance.save() instance.reference2.add(other_model) instance.save() 

我想将其转换为下面的字典:

 {'created': datetime.datetime(2015, 3, 16, 21, 34, 14, 926738, tzinfo=<UTC>), u'id': 1, 'reference1': 1, 'reference2': [1], 'value': 1, 'value2': 2} 

问题回答不理想:

Django:将一整套模型对象转换为单个字典

我怎样才能把Django模型对象转换成一个字典,仍然有他们的外键?

有很多方法可以将实例转换为字典,并具有不同程度的angular落案例处理和接近期望的结果。


1. instance.__dict__

 instance.__dict__ 

哪个返回

 {'_reference1_cache': <OtherModel: OtherModel object>, '_state': <django.db.models.base.ModelState at 0x1f63310>, 'created': datetime.datetime(2014, 2, 21, 4, 38, 51, 844795, tzinfo=<UTC>), 'id': 1L, 'reference1_id': 1L, 'value': 1, 'value2': 2} 

这是迄今为止最简单的,但缺lessreference2,reference1是错误的,它有两个额外的东西。


2. model_to_dict

 from django.forms.models import model_to_dict model_to_dict(instance) 

哪个返回

 {u'id': 1L, 'reference1': 1L, 'reference2': [1L], 'value': 1} 

这是唯一一个reference2,但缺less不可编辑的字段。


3.带有字段的model_to_dict

 from django.forms.models import model_to_dict model_to_dict(instance, fields=[field.name for field in instance._meta.fields]) 

哪个返回

 {u'id': 1L, 'reference1': 1L, 'value': 1} 

这严重地比标准的model_to_dict调用更差。


4. query_set.values()

 SomeModel.objects.filter(id=instance.id).values()[0] 

哪个返回

 {'created': datetime.datetime(2014, 2, 21, 4, 38, 51, tzinfo=<UTC>), u'id': 1L, 'reference1_id': 1L, 'value': 1L, 'value2': 2L} 

这是与instance.__dict__相同的输出,但没有额外的字段。


5.自定义function

Django的model_to_dict的代码有大部分的答案。 它显式删除了不可编辑的字段,因此删除该检查会导致以下代码的行为符合需要:

 from django.db.models.fields.related import ManyToManyField def to_dict(instance): opts = instance._meta data = {} for f in opts.concrete_fields + opts.many_to_many: if isinstance(f, ManyToManyField): if instance.pk is None: data[f.name] = [] else: data[f.name] = list(f.value_from_object(instance).values_list('pk', flat=True)) else: data[f.name] = f.value_from_object(instance) return data 

虽然这是最复杂的选项,调用to_dict(instance)给了我们确切的结果:

 {'created': datetime.datetime(2015, 3, 16, 21, 34, 14, 926738, tzinfo=<UTC>), u'id': 1, 'reference1': 1, 'reference2': [1], 'value': 1, 'value2': 2} 

奖金回合

如果你想要一个更好的python命令行显示的django模型,让你的模型子类如下:

 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)) 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") 

调用SomeModel.objects.first()现在提供这样的输出:

 {'created': datetime.datetime(2015, 3, 16, 21, 34, 14, 926738, tzinfo=<UTC>), 'value': 1, 'value2': 2, 'reference1': 1, u'id': 1, 'reference2': [1]} 

如果你愿意定义你自己的to_dict方法,像@karthikerbuild议的那样,那么这个问题就可以解决问题了。

 >>># Returns a set of all keys excluding editable = False keys >>>dict = model_to_dict(instance) >>>dict {u'id': 1L, 'reference1': 1L, 'reference2': [1L], 'value': 1} >>># Returns a set of editable = False keys, misnamed foreign keys, and normal keys >>>otherDict = SomeModel.objects.filter(id=instance.id).values()[0] >>>otherDict {'created': datetime.datetime(2014, 2, 21, 4, 38, 51, tzinfo=<UTC>), u'id': 1L, 'reference1_id': 1L, 'value': 1L, 'value2': 2L} 

我们需要从otherDict中删除错误标记的外键。

要做到这一点,我们可以使用一个循环来创build一个新的字典,除了那些下划线之外的每个字段。 或者,为了节省时间,我们可以把这些添加到原来的字典,因为字典只是设置在引擎盖下。

 >>>for item in otherDict.items(): ... if "_" not in item[0]: ... dict.update({item[0]:item[1]}) ... >>> 

因此,我们留下以下字典

 >>>dict {'created': datetime.datetime(2014, 2, 21, 4, 38, 51, tzinfo=<UTC>), u'id': 1L, 'reference1': 1L, 'reference2': [1L], 'value': 1, 'value2': 2L} 

而你只是回报。

缺点是,在editable = false字段名称中不能使用下划线。 有利的是,这将适用于用户自定义字段不包含下划线的任何字段。

– 编辑 –

这不是做这件事的最好方法,但它可以作为临时解决scheme,直到find更直接的方法。

对于下面的例子,dict将基于model_to_dict来形成,otherDict将由filter的值方法形成。 我会用模型自己做到这一点,但我不能让我的机器接受其他模型。

 >>> import datetime >>> dict = {u'id': 1, 'reference1': 1, 'reference2': [1], 'value': 1} >>> otherDict = {'created': datetime.datetime(2014, 2, 21, 4, 38, 51), u'id': 1, 'reference1_id': 1, 'value': 1, 'value2': 2} >>> for item in otherDict.items(): ... if "_" not in item[0]: ... dict.update({item[0]:item[1]}) ... >>> dict {'reference1': 1, 'created': datetime.datetime(2014, 2, 21, 4, 38, 51), 'value2': 2, 'value': 1, 'id': 1, 'reference2': [1]} >>> 

我希望这会使你对你的问题的答案有一个粗略的看法。

我find了一个很好的解决scheme来得到结果:

假设你有一个模型对象o

只要打电话:

 type(o).objects.filter(pk=o.pk).values().first() 

@ Zags的解决scheme是美丽的!

不过,我想补充一下datefields的条件,以使其对JSON友好。

奖金回合

如果你想要一个更好的python命令行显示的django模型,让你的模型子类如下:

 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") 

调用SomeModel.objects.first()现在提供这样的输出:

 {'created': 1426552454.926738, 'value': 1, 'value2': 2, 'reference1': 1, u'id': 1, 'reference2': [1]} 

也许这对你有帮助。 可能这不会隐藏许多关系,但是当你想以json格式发送你的模型的时候非常方便。

 def serial_model(modelobj): opts = modelobj._meta.fields modeldict = model_to_dict(modelobj) for m in opts: if m.is_relation: foreignkey = getattr(modelobj, m.name) if foreignkey: try: modeldict[m.name] = serial_model(foreignkey) except: pass return modeldict 

(并不意味着发表评论)

好的,它并不是真的依赖于这种types。 如果是这样,我可能会误解原来的问题,所以原谅我。 如果你创build了serliazers.py然后在那里你创build了具有元类的类。

 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礼貌,所以这是值得研究的。

这里有很多有趣的解决scheme。 我的解决scheme是添加一个as_dict方法到我的模型与字典的理解。

 def as_dict(self): return dict((f.name, getattr(self, f.name)) for f in self._meta.fields) 

作为一个奖励,这个解决scheme与列表理解结合在一起使得查询成为一个很好的解决scheme,如果你想把你的模型导出到另一个库。 例如,将您的模型转储到pandas数据框中:

 pandas_awesomeness = pd.DataFrame([m.as_dict() for m in SomeModel.objects.all()]) 

最简单的方法,

  1. 如果您的查询是Model.Objects.get():

    get()将返回单个实例,所以你可以直接使用__dict__从你的实例

    model_dict = Model.Objects.get().__dict__

  2. 对于filter()/ all():

    all()/ filter()将返回实例列表,以便您可以使用values()来获取对象列表。

    model_values = Model.Objects.all()。values()