平常的开发过程中不免遇到需要把model转成字典的需求,尤其是现在流行前后端分离架构,Json格式几乎成了前后端之间数据交换的标准,这种model转dict的需求就更多了,本文介绍几种日常使用的方法以供参考,所有例子均基于Django 2.0环境演示

背景介绍

model内容如下:

class Group(models.Model):
name = models.CharField(max_length=255, unique=True, verbose_name='组名称') def __str__(self):
return self.name class User(models.Model):
create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
update_time = models.DateTimeField(auto_now=True, verbose_name='更新时间')
username = models.EmailField(max_length=255, unique=True, verbose_name='用户名')
fullname = models.CharField(max_length=64, null=True, verbose_name='中文名')
is_active = models.BooleanField(default=True, verbose_name='激活状态')
leader = models.ForeignKey('self', null=True, on_delete=models.CASCADE, verbose_name='上级')
group = models.ManyToManyField(Group, null=True, verbose_name='所属组') def __str__(self):
return self.username

需求很简单就是分别把Group和User表中的数据转换成字典格式返回

方法一:直接构建字典

示例代码:

>>> _t = Group.objects.get(id=1)
>>>
>>> dict = {
... 'id': _t.id,
... 'name': _t.name
... }
>>>
>>> print(dict)
{'name': 'GroupA', 'id': 1}

这种方法的好处是方便控制最终返回字典value的格式,例如对于User表,我想返回最终的数据是id、创建时间、中文名、上级中文名、所属组名列表的话可以用下边的代码实现

>>> _t = User.objects.get(id=2)
>>>
>>> dict = {
... 'id': _t.id,
... 'create_time': _t.create_time.strftime('%Y-%m-%d %H:%M:%S'),
... 'fullname': _t.fullname if _t.fullname else None,
... 'leader': _t.leader.fullname if _t.leader else None,
... 'group': [ i.name for i in _t.group.all() ],
... }
>>>
>>> print(dict)
{'fullname': '运维咖啡吧', 'group': ['GroupA', 'GroupC', 'GroupE'], 'create_time': '2018-10-12 21:20:19', 'id': 2, 'leader': '公众号'}
>>>

缺点也很明显,就是如果一个model字段很多且不需要转换value格式的时候需要写大量冗余的代码,这种问题怎么解决呢?且看下边的方法介绍

方法二:dict

示例代码:

>>> Group.objects.get(id=1).__dict__
{'id': 1, 'name': 'GroupA', '_state': <django.db.models.base.ModelState object at 0x7f68612daef0>}
>>>
>>> User.objects.get(id=1).__dict__
{'is_active': True, '_state': <django.db.models.base.ModelState object at 0x7f68612fa0b8>, 'id': 1, 'username': 'ops@163.com', 'leader_id': None, 'fullname': '公众号', 'update_time': datetime.datetime(2018, 10, 12, 17, 49, 35, 504141), 'create_time': datetime.datetime(2018, 10, 12, 16, 9, 7, 813660)}

这种方法优点就是写法简单,容易理解,代码量还少

但会发现多了个没用的_state字段,同时Foreignkey字段名多了_id,也没有ManyToManyField字段的数据,且不能按需显示输出,当我只需要其中几个字段时会有大量冗余数据

方法三:model_to_dict

示例代码:

>>> model_to_dict(Group.objects.get(id=1))
{'name': 'GroupA', 'id': 1}
>>>
>>> model_to_dict(User.objects.get(id=2))
{'leader': 1, 'is_active': True, 'username': 'ops-coffee@163.com', 'fullname': '运维咖啡吧', 'group': [<Group: GroupA>, <Group: GroupC>, <Group: GroupE>], 'id': 2}

这种方法能满足大部分的需求,且输出也较为合理,同时还有两个参数fieldsexclude来配置输出的字段,例如:

>>> model_to_dict(User.objects.get(id=2), fields=['fullname','is_active'])
{'is_active': True, 'fullname': '运维咖啡吧'}
>>>
>>> model_to_dict(User.objects.get(id=2), exclude=['group','leader','id'])
{'fullname': '运维咖啡吧', 'is_active': True, 'username': 'ops-coffee@163.com'}

但是会跳过有editable=False属性字段的展示,对于有auto_now_add=Trueauto_now=True属性的datetime字段会默认添加editable=False隐藏属性,这也是上边两个time相关字段create_timeupdate_time转换成dict后不显示的原因,官方相关源码如下:

for f in chain(opts.concrete_fields, opts.private_fields, opts.many_to_many):
if not getattr(f, 'editable', False):
continue

方法四:自定义to_dict

示例代码:

from django.db.models.fields import DateTimeField
from django.db.models.fields.related import ManyToManyField class User(models.Model):
... def to_dict(self, fields=None, exclude=None):
data = {}
for f in self._meta.concrete_fields + self._meta.many_to_many:
value = f.value_from_object(self) if fields and f.name not in fields:
continue if exclude and f.name in exclude:
continue if isinstance(f, ManyToManyField):
value = [ i.id for i in value ] if self.pk else None if isinstance(f, DateTimeField):
value = value.strftime('%Y-%m-%d %H:%M:%S') if value else None data[f.name] = value return data

执行结果:

>>> User.objects.get(id=2).to_dict()
{'is_active': True, 'update_time': '2018-10-12 21:21:39', 'username': 'ops-coffee@163.com', 'id': 2, 'leader': 1, 'group': [1, 3, 5], 'create_time': '2018-10-12 21:20:19', 'fullname': '运维咖啡吧'}
>>>
>>> User.objects.get(id=2).to_dict(fields=['fullname','is_active','create_time'])
{'is_active': True, 'fullname': '运维咖啡吧', 'create_time': '2018-10-12 21:20:19'}
>>>
>>> User.objects.get(id=2).to_dict(exclude=['group','leader','id','create_time'])
{'is_active': True, 'update_time': '2018-10-12 21:21:39', 'username': 'ops-coffee@163.com', 'fullname': '运维咖啡吧'}

拥有model_to_dict一样的便利性,同时也解决了不能输出time时间字段(editable=False)的问题,还能对value按照自己需要的格式输出,一举多得

当然拥有便利性的同时需要自己实现to_dict的代码,增加了复杂度


如果你觉得文章对你有帮助,请转发分享给更多的人。如果你觉得读的不尽兴,推荐阅读以下文章:

Django model转字典的几种方法的更多相关文章

  1. python 3.x 字典的11种方法

    python 3.x 字典的11种方法2017年11月25日 01:02:11 Milton-Long 阅读数:535 标签: python python字典方法 更多个人分类: python-学习之 ...

  2. 提高django model效率的几个小方法

    django的model效率不是很高,特别是在做大量的数据库操作的时候,如果你只用django来开企业站或者外包项目的话,那可以小跳过下,而你恰巧是效率狂或者说是对程序的效率要求比较高的话,那就要注意 ...

  3. 从加载DLL的中获取放置于Resources文件夹中资源字典的几种方法

    原文:从加载DLL的中获取放置于Resources文件夹中资源字典的几种方法 主程序 为 Main_Test.exe 被加载的DLL 为 Load_Test.dll  此DLL 中 有一个 文件夹Re ...

  4. django序列化单表的4种方法的介绍

    这里主要是讲序列化单表的几种方法 先看下models中设计的表结构 from django.db import models # Create your models here. class Book ...

  5. python将字符串转换成字典的几种方法

    当我们遇到类似于{‘a’:1, 'b':2, 'c':3}这种字符串时,想要把它转换成字典进行处理,可以使用以下几种方法: 1. Python自带的eval函数(不安全) dictstr = '{&q ...

  6. Python--合并2个字典成1个新字典的9种方法

    d1 = {'name': 'revotu', 'age': 99} d2 = {'age': 24, 'sex': 'male'} 输出: {'name': 'revotu', 'age': 24, ...

  7. Django扩展Auth-User表的几种方法

    方式1, OneToOneField from django.contrib.auth.models import Userclass UserProfile(models.Model): user ...

  8. django配置静态文件的两种方法

    方法一:按照django配置静态文件的方法,可以在APP应用目录下创建一个static的文件夹,然后在static文件夹下创建一个和APP同名的文件夹,如我有一个blog的django项目,在下面有一 ...

  9. 【Python—字典的用法】创建字典的3种方法

    #创建一个空字典 empty_dict = dict() print(empty_dict) #用**kwargs可变参数传入关键字创建字典 a = dict(one=1,two=2,three=3) ...

随机推荐

  1. 实战--利用SVM对基因表达标本是否癌变的预测

    利用支持向量机对基因表达标本是否癌变的预测 As we mentioned earlier, gene expression analysis has a wide variety of applic ...

  2. CGLIB介绍

    一.什么是CGLIB? CGLIB是一个功能强大,高性能的代码生成包.它为没有实现接口的类提供代理,为JDK的动态代理提供了很好的补充.通常可以使用Java的动态代理创建代理,但当要代理的类没有实现接 ...

  3. Scala深入浅出实战经典:29,Case class和Case object代码实战解析

    今天学习了王家林老师scala讲座的第29讲,case class和case object的应用实战.做下记录. 信息来源于 DT大数据梦工厂微信公众账号:DT_Spark 关注微信账号,获取更多关于 ...

  4. express package.json解析

    教程:http://www.tuicool.com/articles/vuiyIz

  5. (使用STL自带的排序功能进行排序7.3.2)POJ 2092 Grandpa is Famous(结构体排序)

    /* * POJ_2092.cpp * * Created on: 2013年11月1日 * Author: Administrator */ #include <iostream> #i ...

  6. What mind mapping software applications do you recommend.

    选自 https://members.iqmatrix.co/creative-mind-maps I personally use Mindjet MindManager. This is one ...

  7. poj1321 DFS

    棋盘问题 Time Limit: 1000 MS Memory Limit: 10000 KB 64-bit integer IO format: %I64d , %I64u Java class n ...

  8. Android Dagger 2

    Dagger 2 依赖注入 1. 基本概念 最重要有四个概念,也是四个注解(annotation),Provide,Inject,Module,Component. Provide 是提供者,创建实例 ...

  9. 31_网络编程-struct

    一.struct   1.简述  我们可以借助一个模块,这个模块可以把要发送的数据长度转换成固定长度的字节.这样客户端每次接收消息之前只要先接受这个固定长度字节的内容看一看接下来要接收的信息大小,那么 ...

  10. 25_re模块

    一.re模块的核心功能       1.findall —— 查找所有,返回list lst = re.findall("m", "mai le fo len, mai ...