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格式文件的方法
May 11 Python
星球大战与Python之间的那些事
Jan 07 Python
深入浅析python中的多进程、多线程、协程
Jun 22 Python
Python 3中print函数的使用方法总结
Aug 08 Python
Python中按键来获取指定的值
Mar 02 Python
python3使用matplotlib绘制散点图
Mar 19 Python
python多进程读图提取特征存npy
May 21 Python
python正则表达式匹配IP代码实例
Dec 28 Python
Python函数式编程实例详解
Jan 17 Python
python设置环境变量的作用整理
Feb 17 Python
python中判断文件结束符的具体方法
Aug 04 Python
手把手教你怎么用Python实现zip文件密码的破解
May 27 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 不错的学习资料
2009/02/06 PHP
使用PHP实现Mysql读写分离
2013/06/28 PHP
php获得文件夹下所有文件的递归算法的简单实例
2016/11/01 PHP
PHP ADODB生成下拉列表框功能示例
2018/05/29 PHP
Laravel框架执行原生SQL语句及使用paginate分页的方法
2018/08/17 PHP
PHP中使用CURL发送get/post请求上传图片批处理功能
2018/10/15 PHP
JavaScript中的6种运算符总结
2014/10/16 Javascript
jquery日历插件e-calendar升级版
2016/11/10 Javascript
基于BootStrap与jQuery.validate实现表单提交校验功能
2016/12/22 Javascript
微信小程序学习笔记之本地数据缓存功能详解
2019/03/29 Javascript
原生js实现轮播图特效
2020/05/04 Javascript
Vue实现点击导航栏当前标签后变色功能
2020/08/19 Javascript
vue自定义指令和动态路由实现权限控制
2020/08/28 Javascript
[01:28:43]2014 DOTA2华西杯精英邀请赛5 24 DK VS CIS
2014/05/25 DOTA
Linux下通过python访问MySQL、Oracle、SQL Server数据库的方法
2016/04/23 Python
使用python根据端口号关闭进程的方法
2018/11/06 Python
使用python批量化音乐文件格式转换的实例
2019/01/09 Python
情人节快乐! python绘制漂亮玫瑰
2020/08/18 Python
Python中断多重循环的思路总结
2019/10/04 Python
python二维键值数组生成转json的例子
2019/12/06 Python
python 两种方法修改文件的创建时间、修改时间、访问时间
2020/09/26 Python
Python3 用什么IDE开发工具比较好
2020/11/28 Python
详解如何在登录过期后跳出Ifram框架
2020/09/10 HTML / CSS
4s店机修工岗位职责
2013/12/20 职场文书
机械设计职业生涯规划书
2013/12/27 职场文书
办公室主任主任岗位责任制
2014/02/11 职场文书
三分钟英语演讲稿
2014/04/24 职场文书
保证书格式范文
2014/04/28 职场文书
学生干部培训方案
2014/06/12 职场文书
驻村工作简报
2015/07/20 职场文书
反四风问题学习心得体会
2016/01/22 职场文书
创业计划书之个人工作室
2019/08/22 职场文书
2019关于垃圾分类处理的调查报告
2019/12/26 职场文书
Python 流媒体播放器的实现(基于VLC)
2021/04/28 Python
基于Redis结合SpringBoot的秒杀案例详解
2021/10/05 Redis
关于使用Redisson订阅数问题
2022/01/18 Redis