首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >将Django Model对象转换为dict,并保留所有字段

将Django Model对象转换为dict,并保留所有字段
EN

Stack Overflow用户
提问于 2014-02-21 13:02:36
回答 15查看 256.9K关注 0票数 365

如何将django Model对象转换为包含所有字段的dict?理想情况下,在editable=False中包含外键和字段。

让我详细解释一下。假设我有一个如下所示的django模型:

代码语言:javascript
运行
复制
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")

在终端中,我做了以下工作:

代码语言:javascript
运行
复制
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()

我想把它转换成下面的字典:

代码语言:javascript
运行
复制
{'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: Converting an entire set of a Model's objects into a single dictionary

How can I turn Django Model objects into a dictionary and still have their foreign keys?

EN

回答 15

Stack Overflow用户

回答已采纳

发布于 2015-03-17 06:37:54

有许多方法可以将实例转换为字典,具有不同程度的边框大小写处理以及与所需结果的接近程度。

1. instance.__dict__

代码语言:javascript
运行
复制
instance.__dict__

它会返回

代码语言:javascript
运行
复制
{'_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_manyforeign_key命名错误,并且其中有两个不需要的额外内容。

2. model_to_dict

代码语言:javascript
运行
复制
from django.forms.models import model_to_dict
model_to_dict(instance)

它会返回

代码语言:javascript
运行
复制
{'foreign_key': 2,
 'id': 1,
 'many_to_many': [<OtherModel: OtherModel object>],
 'normal_value': 1}

这是唯一一个具有many_to_many的文件,但缺少不可编辑的字段。

3. model_to_dict(..., fields=...)

代码语言:javascript
运行
复制
from django.forms.models import model_to_dict
model_to_dict(instance, fields=[field.name for field in instance._meta.fields])

它会返回

代码语言:javascript
运行
复制
{'foreign_key': 2, 'id': 1, 'normal_value': 1}

这比标准的model_to_dict调用更糟糕。

4. query_set.values()

代码语言:javascript
运行
复制
SomeModel.objects.filter(id=instance.id).values()[0]

它会返回

代码语言:javascript
运行
复制
{'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的代码提供了大部分答案。它显式地删除了不可编辑字段,因此删除检查并获取多对多字段的外键It将导致以下代码的行为符合预期:

代码语言:javascript
运行
复制
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)会给我们提供所需的结果:

代码语言:javascript
运行
复制
{'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允许您从模型自动构建序列化程序。

代码语言:javascript
运行
复制
from rest_framework import serializers
class SomeModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = SomeModel
        fields = "__all__"

SomeModelSerializer(instance).data

返回

代码语言:javascript
运行
复制
{'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模型,让你的模型子类如下:

代码语言:javascript
运行
复制
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

例如,如果我们这样定义我们的模型:

代码语言:javascript
运行
复制
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()会产生如下输出:

代码语言:javascript
运行
复制
{'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}
票数 749
EN

Stack Overflow用户

发布于 2016-04-30 08:27:02

我找到了一个简洁的解决方案来得到结果:

假设您有一个模型对象o

只需拨打:

代码语言:javascript
运行
复制
type(o).objects.filter(pk=o.pk).values().first()
票数 10
EN

Stack Overflow用户

发布于 2018-02-18 23:55:54

只需vars(obj),它将声明对象的所有值

代码语言:javascript
运行
复制
>>> obj_attrs = vars(obj)
>>> obj_attrs
 {'_file_data_cache': <FileData: Data>,
  '_state': <django.db.models.base.ModelState at 0x7f5c6733bad0>,
  'aggregator_id': 24,
  'amount': 5.0,
  'biller_id': 23,
  'datetime': datetime.datetime(2018, 1, 31, 18, 43, 58, 933277, tzinfo=<UTC>),
  'file_data_id': 797719,
 }

您还可以添加此内容

代码语言:javascript
运行
复制
>>> keys = obj_attrs.keys()
>>> temp = [obj_attrs.pop(key) if key.startswith('_') else None for key in keys]
>>> del temp
>>> obj_attrs
   {
    'aggregator_id': 24,
    'amount': 5.0,
    'biller_id': 23,
    'datetime': datetime.datetime(2018, 1, 31, 18, 43, 58, 933277, tzinfo=<UTC>),
    'file_data_id': 797719,
   }
票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/21925671

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档