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实现批量把SVG格式转成png、pdf格式的代码分享
Aug 21 Python
利用 Monkey 命令操作屏幕快速滑动
Dec 07 Python
Python Nose框架编写测试用例方法
Oct 26 Python
Python使用pip安装pySerial串口通讯模块
Apr 20 Python
用Python和WordCloud绘制词云的实现方法(内附让字体清晰的秘笈)
Jan 08 Python
matplotlib.pyplot绘图显示控制方法
Jan 15 Python
python 实现敏感词过滤的方法
Jan 21 Python
Python如何测试stdout输出
Aug 10 Python
Python pip 常用命令汇总
Oct 19 Python
Pyecharts 中Geo函数常用参数的用法说明
Feb 01 Python
解决pytorch 保存模型遇到的问题
Mar 03 Python
python实现三次密码验证的示例
Apr 29 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
全国FM电台频率大全 - 17 湖北省
2020/03/11 无线电
PHP 截取字符串 分别适合GB2312和UTF8编码情况
2009/02/12 PHP
IIS7.X配置PHP运行环境小结
2011/06/09 PHP
php中替换字符串中的空格为逗号','的方法
2014/06/09 PHP
PHP简单判断字符串是否包含另一个字符串的方法
2016/03/25 PHP
PHP使用pear实现mail发送功能 windows环境下配置pear
2016/04/15 PHP
PHP+Apache+Mysql环境搭建教程
2016/08/01 PHP
ie focus bug 解决方法
2009/09/03 Javascript
Chrome Form多次提交表单问题的解决方法
2011/05/09 Javascript
javascript开发随笔二 动态加载js和文件
2011/11/25 Javascript
jQuery实现视频作为全屏幕背景
2014/12/18 Javascript
多功能jQuery树插件zTree实现权限列表简单实例
2016/07/12 Javascript
Avalonjs 实现简单购物车功能(实例代码)
2017/02/07 Javascript
深入理解在JS中通过四种设置事件处理程序的方法
2017/03/02 Javascript
AngularJS实现的JSONP跨域访问数据传输功能详解
2017/07/20 Javascript
vue 配置多页面应用的示例代码
2018/10/22 Javascript
UEditor 自定义图片视频尺寸校验功能的实现代码
2020/10/20 Javascript
antd日期选择器禁止选择当天之前的时间操作
2020/10/29 Javascript
python执行使用shell命令方法分享
2017/11/08 Python
Django中的文件的上传的几种方式
2018/07/23 Python
对python 多个分隔符split 的实例详解
2018/12/20 Python
python使用minimax算法实现五子棋
2019/07/29 Python
Python 继承,重写,super()调用父类方法操作示例
2019/09/29 Python
Python 实现 T00ls 自动签到脚本代码(邮件+钉钉通知)
2020/07/06 Python
Django DRF APIView源码运行流程详解
2020/08/17 Python
python实现快速文件格式批量转换的方法
2020/10/16 Python
地球上最先进的胡子和头发修剪器:Bevel
2018/01/23 全球购物
《找不到快乐的波斯猫》教学反思
2014/02/24 职场文书
项目经理任命书内容
2014/06/06 职场文书
单位活动策划方案
2014/08/17 职场文书
四风个人对照检查材料思想汇报(办公室通用版)
2014/10/07 职场文书
医院志愿者活动总结
2015/05/06 职场文书
新娘婚礼答谢词
2015/09/29 职场文书
2021年国产动漫公司排行前十名,玄机科技上榜,第二推出过铠甲勇士
2022/03/18 杂记
《极主夫道》真人电影正式预告 定档6月3日上映
2022/04/05 日漫
mybatis 获取更新记录的id
2022/05/20 Java/Android