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制作爬虫爬取京东商品评论教程
Dec 16 Python
Python DataFrame 设置输出不显示index(索引)值的方法
Jun 07 Python
python使用正则表达式来获取文件名的前缀方法
Oct 21 Python
如何在Python中实现goto语句的方法
May 18 Python
使用pytorch和torchtext进行文本分类的实例
Jan 08 Python
django迁移文件migrations的实现
Mar 31 Python
django执行原始查询sql,并返回Dict字典例子
Apr 01 Python
在Python中使用K-Means聚类和PCA主成分分析进行图像压缩
Apr 10 Python
简单了解python shutil模块原理及使用方法
Apr 28 Python
python用tkinter实现一个gui的翻译工具
Oct 26 Python
利用Python实现自动扫雷小脚本
Dec 17 Python
Python 流媒体播放器的实现(基于VLC)
Apr 28 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
如何把PHP转成EXE文件
2006/10/09 PHP
PHP中CURL方法curl_setopt()函数的参数分享
2013/01/19 PHP
Laravel框架中VerifyCsrfToken报错问题的解决
2017/08/30 PHP
laravel5.1框架model类查询的实现方法
2019/10/08 PHP
js数字输入框(包括最大值最小值限制和四舍五入)
2009/11/24 Javascript
jQuery控制的不同方向的滑动(向左、向右滑动等)
2014/07/18 Javascript
javascript刷新父页面的各种方法汇总
2014/09/03 Javascript
javaScript中Math()函数注意事项
2015/06/18 Javascript
jquery显示loading图片直到网页加载完成的方法
2015/06/25 Javascript
如何利用模板将HTML从JavaScript中抽离
2016/10/08 Javascript
jQuery使用JSONP实现跨域获取数据的三种方法详解
2017/05/04 jQuery
关于echarts在节点显示动态数据及添加提示文本所遇到的问题
2018/04/20 Javascript
javascript中关于类型判断的一些疑惑小结
2018/10/14 Javascript
原生javascript的ajax请求及后台PHP响应操作示例
2020/02/24 Javascript
javascript用defineProperty实现简单的双向绑定方法
2020/04/03 Javascript
JavaScript 监听组合按键思路及代码实现
2020/07/28 Javascript
[02:06]DOTA2英雄基础教程 暗影萨满
2013/12/16 DOTA
[04:54]DOTA2 2017国际邀请赛:上届冠军WINGS采访短片
2017/08/09 DOTA
python列表与元组详解实例
2013/11/01 Python
Python下线程之间的共享和释放示例
2015/05/04 Python
Python2中的raw_input() 与 input()
2015/06/12 Python
使用Python绘制图表大全总结
2017/02/11 Python
Python对字符串实现去重操作的方法示例
2017/08/11 Python
对python中xlsx,csv以及json文件的相互转化方法详解
2018/12/25 Python
Python3实现的简单三级菜单功能示例
2019/03/12 Python
详解Django admin高级用法
2019/11/06 Python
python将dict中的unicode打印成中文实例
2020/05/11 Python
简单掌握CSS3将文字描边及填充文字颜色的方法
2016/03/07 HTML / CSS
HTML5在IE10、火狐下中文乱码问题的解决方法
2013/11/18 HTML / CSS
Html5实现文件异步上传功能
2017/05/19 HTML / CSS
澳大利亚最大的护发和护肤品购物网站:RY
2019/12/26 全球购物
学生会竞选演讲稿
2014/04/24 职场文书
“向国旗敬礼”主题班会活动设计方案
2014/09/27 职场文书
2014年组织部工作总结
2014/11/14 职场文书
浅析Python中的随机采样和概率分布
2021/12/06 Python
Vue+TypeScript中处理computed方式
2022/04/02 Vue.js