将 Django 模型对象转换为 dict,所有字段都完好无损 [英] Convert Django Model object to dict with all of the fields intact

查看:40
本文介绍了将 Django 模型对象转换为 dict,所有字段都完好无损的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何将 django 模型对象转换为具有所有字段的字典?理想情况下,所有这些都包括具有 editable=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_manyforeign_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,所有字段都完好无损的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆