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实现的udp协议Server和Client代码实例
Jun 04 Python
Python编程中对super函数的正确理解和用法解析
Jul 02 Python
Python中几种导入模块的方式总结
Apr 27 Python
详谈Python2.6和Python3.0中对除法操作的异同
Apr 28 Python
Python3多线程爬虫实例讲解代码
Jan 05 Python
python验证码识别教程之滑动验证码
Jun 04 Python
python处理数据,存进hive表的方法
Jul 04 Python
利用django+wechat-python-sdk 创建微信服务器接入的方法
Feb 20 Python
深入浅析Python 中的sklearn模型选择
Oct 12 Python
Python利用多线程同步锁实现多窗口订票系统(推荐)
Dec 22 Python
python调用百度API实现人脸识别
Nov 17 Python
在 Golang 中实现 Cache::remember 方法详解
Mar 30 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 HTML代码串 截取实现代码
2009/06/29 PHP
PHP添加文字水印或图片水印的水印类完整源代码与使用示例
2019/03/18 PHP
javascript中万恶的function实例分析
2011/05/25 Javascript
jQuery.fn和jQuery.prototype区别介绍
2013/10/05 Javascript
一个网页标题title的闪动提示效果实现思路
2014/03/22 Javascript
jquery实现LED广告牌旋转系统图片切换效果代码分享
2015/08/26 Javascript
JavaScript脚本判断蜘蛛来源的方法
2015/09/22 Javascript
Bootstrap每天必学之轮播(Carousel)插件
2016/04/25 Javascript
XMLHttpRequest Level 2 使用指南
2016/08/26 Javascript
javascript 闭包详解及简单实例应用
2016/12/31 Javascript
angular写一个列表的选择全选交互组件的示例
2018/01/22 Javascript
Koa2 之文件上传下载的示例代码
2018/03/29 Javascript
react native 文字轮播的实现示例
2018/07/27 Javascript
css配合JavaScript实现tab标签切换效果
2018/10/11 Javascript
vue实现可视化可拖放的自定义表单的示例代码
2019/03/20 Javascript
小程序登录/注册页面设计的实现代码
2019/05/24 Javascript
OpenLayers3实现鼠标移动显示坐标
2020/09/25 Javascript
零基础写python爬虫之使用Scrapy框架编写爬虫
2014/11/07 Python
python实现颜色rgb和hex相互转换的函数
2015/03/19 Python
Python程序中用csv模块来操作csv文件的基本使用教程
2016/03/03 Python
Python之pandas读写文件乱码的解决方法
2018/04/20 Python
Python3.6.0+opencv3.3.0人脸检测示例
2018/05/25 Python
Python根据指定日期计算后n天,前n天是哪一天的方法
2018/05/29 Python
python自定义函数实现一个数的三次方计算方法
2019/01/20 Python
pandas读取CSV文件时查看修改各列的数据类型格式
2019/07/07 Python
django ManyToManyField多对多关系的实例详解
2019/08/09 Python
Python3 requests文件下载 期间显示文件信息和下载进度代码实例
2019/08/16 Python
Python操作redis和mongoDB的方法
2019/12/19 Python
django 装饰器 检测登录状态操作
2020/07/02 Python
2014年圣诞节倒计时网页的制作过程
2014/12/05 HTML / CSS
HTML5 input新增type属性color颜色拾取器的实例代码
2018/08/27 HTML / CSS
The North Face北面法国官网:美国著名户外品牌
2019/11/01 全球购物
给小学生的新年寄语
2014/04/04 职场文书
国际贸易毕业生自荐书
2014/06/22 职场文书
2014年个人委托书范本
2014/10/13 职场文书
Python使用sql语句对mysql数据库多条件模糊查询的思路详解
2021/04/12 Python