Django 再谈一谈json序列化


Posted in Python onMarch 16, 2020

我们知道JSON字符串是目前流行的数据交换格式,在pyhton中我们通过json模块,将常用的数据类型转化为json字符串。但是,json支持转化的数据类型是有限的。

比如,我们通过ORM从数据库查询出的结果,试图通过json序列化:

from .models import UserInfo

def index(request):
  user_list = UserInfo.objects.all()
  import json
  return HttpResponse(json.dumps(user_list))
  # TypeError: Object of type 'QuerySet' is not JSON serializable

报错,QuerySet不是JSON能序列化的对象。那么有什么办法可以解决呢?

注意,如果是通过values查询,如UserInfo.objects.values("name"),查询出来的结果虽然也是QuerySet对象,但是其结构是这样的:<QuerySet [{'name': 'egon'}, {'name': 'sb'}]>, 类似于列表套字典的结构。对于这种情况,我们可以通过list()方法将QuerySet 对象转化为列表,这样就可以直接用json.dumps()进行序列化了。

方法一:serializers

def index(request):
  user_list = UserInfo.objects.all()
  from django.core import serializers
  user_list_json = serializers.serialize("json", user_list)
  return HttpResponse(user_list_json)

将返回的结果放到bejson校验结果如下:

[
 {
  "model": "app01.userinfo",
  "pk": 1,  
  "fields": {
    "name": "egon",
    "pwd": "123"
  }
},
{
  "model": "app01.userinfo",
  "pk": 2,
  "fields": {
    "name": "sb",
    "pwd": "123"
  }
}
]

注:pk代表主键(可以是默认的id主键字段,也可以是用户自定义的主键字段)

观察序列化结果,发现这种方式将服务端数据库的表名都暴露了;另外serializers不支持连表序列化,只能拿到另一张表的id。下面我们我们用一种新的方式。

方法二:自定义JSON处理器

查看json.dumps源码,发现序列化时,用到了一个参数cls = JSONEncoder,我们可以继承它,自定义一个类,重写它的default方法,来处理我们需要的数据类型。比如自定义对时间对象进行转化:

import json
from datetime import date
from datetime import datetime

class JsonCustomEncoder(json.JSONEncoder):

  def default(self, field):

    if isinstance(field, datetime):
      return field.strftime('%Y-%m-%d %H:%M:%S')
    elif isinstance(field, date):
      return field.strftime('%Y-%m-%d')
    else:
      return json.JSONEncoder.default(self, field)

下面我们试着序列化一个datetime对象:

def index(request):
  now = datetime.now()
  import json
  return HttpResponse(json.dumps(now, cls=JsonCustomEncoder))

再次访问http://127.0.0.1:8000/index.html:

Django 再谈一谈json序列化

补充知识:Django ORM对象Json序列化问题

碰到了一个问题:在使用json.dumps()序列化Django ORM的Queryset对象,传递给前端的时候,程序报错:

Object of type 'QuerySet' is not JSON serializable

在python 中,常用的json 的序列化是从simplejson 基础上改变而来。这个json 包主要提供了dump,load 来实现dict 与 字符串之间的序列化与反序列化,这很方便的可以完成,但现在的问题是,这个json包不能序列化 django 的models 里面的对象的实例。

经过一番度娘搜索,发现有如下解决方案:

使用django.core自带的serializers模块:

#django ORM的 Queryset对象默认无法被直接json.dumps()序列化,django.core提供的serializers模块提供将其序列化成str类型
#的功能,serializers处理后,再次json.dumps传给前端,前端需要经过两次json.Parse()处理,才能得到原对象类型,但是格式发
#生了变化,需要按新的方式取索引.例如:obj['pk']取主键,obj['fields']["caption"]取obj的caption字段
由QuerySet:[<Business: Business object>]
变为了:
[{"model": "cmdb.business", "pk": 1, "fields": {"caption": "develop"}}]

这样前端就可以正常获取数据了,只不过此字段需要两次json.Parse()处理。

至于使用models.Host.objects.get(id=xx)的方式获取到单个对象,而非Queryset对象,serializers默认也无法处理的问题,可以自定义json方法来实现dumps序列化

json默认只支持python原生的list、tuple、dict数据类型对象的序列化,若需要扩展其他类型对象的序列化功能,可以这样修改:

import json as default_json
from json.encoder import JSONEncoder


class BaseResponse(object):
  def __init__(self):
    self.status = True
    self.message = None
    self.data = None
    self.error = None
o=BaseResponse()

class JsonCustomEncoder(JSONEncoder):
  def default(self, o):
    if isinstance(o, BaseResponse):
      return o.__dict__
    return JSONEncoder.default(self, o)

o1=json.dumps(o,cls=JsonCustomEncoder)


>>> print(o1)
{"message": null, "error": null, "data": null, "status": true}
>>> print(type(o1))
<class 'str'>
#在序列化时指定cls参数,cls=自定义的序列化类,在自定义序列化类的default方法中判断,如果是指定的类的实例的话,则将该类转换成dict格式返回,若指定类的实例,则使用json模块默认的序列化方法。最终得到的return值为str类型。

以上这篇Django 再谈一谈json序列化就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
使用PDB模式调试Python程序介绍
Apr 05 Python
python 添加用户设置密码并发邮件给root用户
Jul 25 Python
linux平台使用Python制作BT种子并获取BT种子信息的方法
Jan 20 Python
python使用 HTMLTestRunner.py生成测试报告
Oct 20 Python
微信跳一跳python辅助软件思路及图像识别源码解析
Jan 04 Python
关于sys.stdout和print的区别详解
Dec 05 Python
将 Ubuntu 16 和 18 上的 python 升级到最新 python3.8 的方法教程
Mar 11 Python
解决安装新版PyQt5、PyQT5-tool后打不开并Designer.exe提示no Qt platform plugin的问题
Apr 24 Python
python爬虫数据保存到mongoDB的实例方法
Jul 28 Python
pytorch中index_select()的用法详解
Jan 06 Python
python 算法题——快乐数的多种解法
May 27 Python
关于 Python json中load和loads区别
Nov 07 Python
django实现将后台model对象转换成json对象并传递给前端jquery
Mar 16 #Python
Python读写操作csv和excle文件代码实例
Mar 16 #Python
django模型动态修改参数,增加 filter 字段的方式
Mar 16 #Python
Python Django2 model 查询介绍(条件、范围、模糊查询)
Mar 16 #Python
python高阶函数map()和reduce()实例解析
Mar 16 #Python
Django models filter筛选条件详解
Mar 16 #Python
python递归调用中的坑:打印有值, 返回却None
Mar 16 #Python
You might like
阿拉伯的咖啡与水烟
2021/03/03 咖啡文化
PHP实现在线阅读PDF文件的方法
2015/06/17 PHP
PHP无限极分类函数的实现方法详解
2017/04/15 PHP
浅谈javascript的数据类型检测
2010/07/10 Javascript
JS Range HTML文档/文字内容选中、库及应用介绍
2011/05/12 Javascript
jquery全选checkBox功能实现代码(取消全选功能)
2013/12/10 Javascript
JavaScript的arguments对象应用示例
2014/09/15 Javascript
DOM基础教程之使用DOM控制表单
2015/01/20 Javascript
js实现最短的XML格式化工具实例
2015/03/12 Javascript
HTML页面定时跳转方法解析(2种任选)
2016/12/22 Javascript
JavaScript使用原型和原型链实现对象继承的方法详解
2017/04/05 Javascript
JS排序之选择排序详解
2017/04/08 Javascript
weui框架实现上传、预览和删除图片功能代码
2017/08/24 Javascript
vue自定义指令实现方法详解
2019/02/11 Javascript
Vue实现微信支付功能遇到的坑
2019/06/05 Javascript
JavaScript自动生成 年月范围 选择功能完整示例【基于jQuery插件】
2019/09/03 jQuery
JavaScript Array对象使用方法解析
2019/09/24 Javascript
[04:23]DOTA2上海特锦赛小组赛第一日 TOP10精彩集锦
2016/02/27 DOTA
使用PDB模式调试Python程序介绍
2015/04/05 Python
Python实现的文本编辑器功能示例
2017/06/30 Python
Python中序列的修改、散列与切片详解
2017/08/27 Python
python3反转字符串的3种方法(小结)
2019/11/07 Python
python实发邮件实例详解
2019/11/11 Python
Eclipse配置python默认头过程图解
2020/04/26 Python
Python基于当前时间批量创建文件
2020/05/07 Python
Python之字典添加元素的几种方法
2020/09/30 Python
Canvas 文本填充线性渐变的使用详解
2020/06/22 HTML / CSS
东芝官网商城:还原日式美学,打造美好生活
2018/12/27 全球购物
佳能法国商店:Canon法国
2019/02/14 全球购物
年度考核自我鉴定
2014/02/02 职场文书
公司领导班子对照材料
2014/08/18 职场文书
销售会议开幕词
2016/03/04 职场文书
旅游安全责任协议书
2016/03/22 职场文书
合作意向书怎么写
2019/06/24 职场文书
对Keras自带Loss Function的深入研究
2021/05/25 Python
CSS实现切角+边框+投影+内容背景色渐变效果
2021/11/01 HTML / CSS