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实现定制交互式命令行的方法
Jul 03 Python
利用Python生成文件md5校验值函数的方法
Jan 10 Python
Python编写一个闹钟功能
Jul 11 Python
Python3.4编程实现简单抓取爬虫功能示例
Sep 14 Python
python中实现精确的浮点数运算详解
Nov 02 Python
tensorflow输出权重值和偏差的方法
Feb 10 Python
python使用Paramiko模块实现远程文件拷贝
Apr 30 Python
python实现字符串完美拆分split()的方法
Jul 16 Python
Django-xadmin+rule对象级权限的实现方式
Mar 30 Python
完美解决keras 读取多个hdf5文件进行训练的问题
Jul 01 Python
基于Python制作一副扑克牌过程详解
Oct 19 Python
使用python对excel表格处理的一些小功能
Jan 25 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
PHP5.5安装PHPRedis扩展及连接测试方法
2017/01/22 PHP
php读取出一个文件夹及其子文件夹下所有文件的方法示例
2017/06/15 PHP
带左右箭头图片轮播的JS代码
2013/12/18 Javascript
Jquery设置attr的disabled属性控制某行显示或者隐藏
2014/09/25 Javascript
JavaScript前端开发之实现二进制读写操作
2015/11/04 Javascript
将JavaScript的jQuery库中表单转化为JSON对象的方法
2015/11/17 Javascript
js实现索引图片切换效果
2015/11/21 Javascript
Javascript点击按钮随机改变数字与其颜色
2016/09/01 Javascript
JavaScript正则表达式实例详解
2016/10/16 Javascript
BootStrap Table 后台数据绑定、特殊列处理、排序功能
2017/05/27 Javascript
nodejs接入阿里大鱼短信验证码的方法
2017/07/10 NodeJs
javascript的this关键字详解
2019/05/20 Javascript
Vue过渡效果之CSS过渡详解(结合transition,animation,animate.css)
2020/02/05 Javascript
javascript中contains是否包含功能实现代码(扩展字符、数组、dom)
2020/04/07 Javascript
加速vue组件渲染之性能优化
2020/04/09 Javascript
JS JQuery获取data-*属性值方法解析
2020/09/01 jQuery
windows如何把已安装的nodejs高版本降级为低版本(图文教程)
2020/12/14 NodeJs
Python中的引用和拷贝浅析
2014/11/22 Python
Python多线程编程(一):threading模块综述
2015/04/05 Python
python实现随机漫步算法
2018/08/27 Python
Python实现从SQL型数据库读写dataframe型数据的方法【基于pandas】
2019/03/18 Python
详解python数据结构和算法
2019/04/18 Python
Python/Django后端使用PIL Image生成头像缩略图
2019/04/30 Python
Python多线程:主线程等待所有子线程结束代码
2020/04/25 Python
Python logging模块写入中文出现乱码
2020/05/21 Python
H&M旗下高端女装品牌:& Other Stories
2018/05/07 全球购物
Electrolux伊莱克斯巴西商店:家用电器、小家电和配件
2018/05/23 全球购物
运动鞋、足球鞋和慕尼黑球衣:Sport Münzinger
2019/08/26 全球购物
毕业生毕业总结的自我评价范文
2013/11/02 职场文书
马智宇婚礼主持词
2014/03/22 职场文书
《望庐山瀑布》教学反思
2014/04/22 职场文书
住宅质量保证书
2014/04/29 职场文书
公司募捐倡议书
2014/05/14 职场文书
Django给表单添加honeypot验证增加安全性
2021/05/06 Python
Python Flask搭建yolov3目标检测系统详解流程
2021/11/07 Python
JavaScript流程控制(循环)
2021/12/06 Javascript