Django model序列化为json的方法示例


Posted in Python onOctober 16, 2018

本文环境

  • Python 3.6.5
  • Django 2.0.4

fix(2018.5.19):最近得知Django 的model基类需要声明为abstract,故在原来的代码加入abstract声明,以免误导

在Django中,关于如何将model类序列化为json,一般的话有两a器

将model类转为字典,再使用json库的dumps方法转为json

第一种方法就不多讲了,直接去看官方文档就好啦

一般来说,官方提供的方法应该都是比较好用和稳定的,然而,使用官方的序列化器却问题不少:

格式丑陋,格式如下,一言难尽:

[
  {
    "pk": "4b678b301dfd8a4e0dad910de3ae245b",
    "model": "sessions.session",
    "fields": {
      "expire_date": "2013-01-16T08:16:59.844Z",
      ...
    }
  }
]

是的,其中pk指的是默认主键,model指的是该object的model类型,然后fields才是obj的各种字段...真的是不知如何评价了

  • 不能很好地支持list
  • 对于一些外键(包括ManyToManyField等)不是很友好
  • 甚至对于自身的DateField也没有很好的支持

数了一通官方序列化器的缺点,当然了,上面的几个点肯定是有解决方案的,但是啊,我确实不想折腾了嘤嘤嘤。

于是扔出我的解决方案:

  • 新建一个类BaseModel,此类继承于官方的model类django.db.models.Model
  • 在着个BaseModel中,声明一个方法,此方法用于生成关于这个object的字典
  • 使用这个object的字典生成json

关于生成object的字典的策略是这样的:

  • 通过反射获取这个object的所有字段名
  • 根据字段名获得某个字段field
  • 如果filed的类型的是int、float、str的话,直接将以 "字段名":字段值 的形式放入字典中
  • 若field的类型是datetime或者date的话,使用date的方式处理,然后放入字典
  • 若field的类型是BaseModel的话,那么就调用该field的getDict方法递归获得该field对应的字典,然后放入字典中
  • 若field的类型是ManyToMany类型,在具体草种中我们使用这个field的all方法来这个field的所有object,然后也是通过getDict方法将其放入到字典中

源码及使用方法

from django.db import models
import json


class BaseModel(models.Model):
  class Meta:
    abstract = True

  # 返回self._meta.fields中没有的,但是又是需要的字段名的列表
  # 形如['name','type']
  def getMtMField(self):
    pass

  # 返回需要在json中忽略的字段名的列表
  # 形如['password']
  def getIgnoreList(self):
    pass

  def isAttrInstance(self, attr, clazz):
    return isinstance(getattr(self, attr), clazz)

  def getDict(self):
    fields = []
    for field in self._meta.fields:
      fields.append(field.name)

    d = {}
    import datetime
    for attr in fields:
      if isinstance(getattr(self, attr), datetime.datetime):
        d[attr] = getattr(self, attr).strftime('%Y-%m-%d %H:%M:%S')
      elif isinstance(getattr(self, attr), datetime.date):
        d[attr] = getattr(self, attr).strftime('%Y-%m-%d')
      # 特殊处理datetime的数据
      elif isinstance(getattr(self, attr), BaseModel):
        d[attr] = getattr(self, attr).getDict()
      # 递归生成BaseModel类的dict
      elif self.isAttrInstance(attr, int) or self.isAttrInstance(attr, float) \
          or self.isAttrInstance(attr, str):
        d[attr] = getattr(self, attr)
      # else:
      #   d[attr] = getattr(self, attr)

    mAttr = self.getMtMField()
    if mAttr is not None:
      for m in mAttr:
        if hasattr(self, m):
          attlist = getattr(self, m).all()
          l = []
          for attr in attlist:
            if isinstance(attr, BaseModel):
              l.append(attr.getDict())
            else:
              dic = attr.__dict__
              if '_state' in dic:
                dic.pop('_state')
              l.append(dic)
          d[m] = l
    # 由于ManyToMany类不能存在于_meat.fields,因而子类需要在getMtMFiled中返回这些字段
    if 'basemodel_ptr' in d:
      d.pop('basemodel_ptr')

    ignoreList = self.getIgnoreList()
    if ignoreList is not None:
      for m in ignoreList:
        if d.get(m) is not None:
          d.pop(m)
    # 移除不需要的字段
    return d

  def toJSON(self):
    import json
    return json.dumps(self.getDict(), ensure_ascii=False).encode('utf-8').decode()

使用方法:

models的所有类都继承BaseModel类,然后调用此类的toJSON()方法即可

注意,不知为何,self._meta.fields中没有包含ManyToManyField字段,因而需要重写getMtMField方法。例子如下:

class Book(BaseModel):
  name = models.CharField(max_length=50)
  authors = models.ManyToManyField(Author)
  publish = models.ForeignKey(Publisher, on_delete=models.SET_NULL, blank=True, null=True)
  page = models.IntegerField(default=0) # 页数
  introduction = models.CharField(max_length=500)
  bookType = models.ManyToManyField(BookType, null=True, blank=True)
  bookTag = models.ManyToManyField(BookTag, null=True, blank=True)
  evaluation = models.FloatField()
  coverUrl = models.CharField(max_length=100, null=True, blank=True)

  def getMtMField(self):
    return ['bookType', 'bookTag']

结果:

{
  "id":4,
  "name":"Django从入门到放弃",
  "page":123,
  "introduction":"introduction",
  "evaluation":1,
  "bookType":[
    {
      "id":1,
      "name":"类型"
    }
  ],
  "bookTag":[
    {
      "id":2,
      "name":"tag"
    }
  ]
}

后记

源码有引用,即getDict方法中的第一个for循环,但懒得找原链接了,望见谅,特此声明;

  • 本人python新手,代码多有不规范之处,望见谅;
  • 代码不精,但是也希望能帮到你_;

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python解析xml模块封装代码
Feb 07 Python
python简单程序读取串口信息的方法
Mar 13 Python
python使用webbrowser浏览指定url的方法
Apr 04 Python
python监控文件并且发送告警邮件
Jun 21 Python
python读取LMDB中图像的方法
Jul 02 Python
解决Mac下首次安装pycharm无project interpreter的问题
Oct 29 Python
对Python强大的可变参数传递机制详解
Jun 13 Python
在pandas中遍历DataFrame行的实现方法
Oct 23 Python
django admin 添加自定义链接方式
Mar 11 Python
Django models文件模型变更错误解决
May 11 Python
Python-openCV开运算实例
Jul 05 Python
python 密码学示例——理解哈希(Hash)算法
Sep 21 Python
Python重新加载模块的实现方法
Oct 16 #Python
django Serializer序列化使用方法详解
Oct 16 #Python
为什么str(float)在Python 3中比Python 2返回更多的数字
Oct 16 #Python
对python添加模块路径的三种方法总结
Oct 16 #Python
Python中的CSV文件使用"with"语句的方式详解
Oct 16 #Python
详解django的serializer序列化model几种方法
Oct 16 #Python
Python调用C++,通过Pybind11制作Python接口
Oct 16 #Python
You might like
人工智能开始玩《星际争霸2》 你的操作跟得上吗?
2017/08/11 星际争霸
php页码形式分页函数支持静态化地址及ajax分页
2014/03/28 PHP
php实现的常见排序算法汇总
2014/09/08 PHP
thinkPHP5.0框架事务处理操作简单示例
2018/09/07 PHP
laravel中数据显示方法(默认值和下拉option默认选中)
2019/10/11 PHP
php实现银联商务公众号+服务窗支付的示例代码
2019/10/12 PHP
PHP如何使用JWT做Api接口身份认证的实现
2020/02/03 PHP
Centos7安装swoole扩展操作示例
2020/03/26 PHP
鼠标图片振动代码
2006/07/06 Javascript
Jquery升级新版本后选择器的语法问题
2010/06/02 Javascript
js获取class的所有元素
2013/03/28 Javascript
jQuery实现平滑滚动到指定锚点的方法
2015/03/20 Javascript
node koa2实现上传图片并且同步上传到七牛云存储
2017/07/31 Javascript
AngularJs+Bootstrap实现漂亮的计算器
2017/08/10 Javascript
parabola.js抛物线与加入购物车效果的示例代码
2017/10/25 Javascript
响应式框架Bootstrap栅格系统的实例
2017/12/19 Javascript
微信小程序数字滚动插件使用详解
2018/02/02 Javascript
解决vue-router中的query动态传参问题
2018/03/20 Javascript
vue中接口域名配置为全局变量的实现方法
2018/09/20 Javascript
详解iframe跨域的几种常用方法(小结)
2019/04/29 Javascript
解决vue页面刷新,数据丢失的问题
2020/11/24 Vue.js
angular *Ngif else用法详解
2020/12/15 Javascript
[01:24]DOTA2上海特锦赛OG战队抵达 专车接机入驻总统套房
2016/02/23 DOTA
[02:13] 完美世界DOTA2联赛PWL DAY5集锦
2020/11/03 DOTA
简单的编程0基础下Python入门指引
2015/04/01 Python
Python实现多线程HTTP下载器示例
2017/02/11 Python
30秒轻松实现TensorFlow物体检测
2018/03/14 Python
Python文件操作中进行字符串替换的方法(保存到新文件/当前文件)
2019/06/28 Python
pandas 使用均值填充缺失值列的小技巧分享
2019/07/04 Python
Python 写入训练日志文件并控制台输出解析
2019/08/13 Python
Pycharm+Python工程,引用子模块的实现
2020/03/09 Python
keras 两种训练模型方式详解fit和fit_generator(节省内存)
2020/07/03 Python
档案接收函
2014/01/13 职场文书
《月球之谜》教学反思
2014/04/10 职场文书
行政专员岗位职责说明书
2014/07/30 职场文书
德劲DE1108畅想
2021/04/22 无线电