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 相关文章推荐
python中关于日期时间处理的问答集锦
Mar 08 Python
python实现指定字符串补全空格的方法
Apr 30 Python
Python学习教程之常用的内置函数大全
Jul 14 Python
python 删除大文件中的某一行(最有效率的方法)
Aug 19 Python
go和python变量赋值遇到的一个问题
Aug 31 Python
Python使用Pickle库实现读写序列操作示例
Jun 15 Python
python 循环读取txt文档 并转换成csv的方法
Oct 26 Python
详解opencv Python特征检测及K-最近邻匹配
Jan 21 Python
python 获得任意路径下的文件及其根目录的方法
Feb 16 Python
详解用python写一个抽奖程序
May 10 Python
利用anaconda保证64位和32位的python共存
Mar 09 Python
Python 按比例获取样本数据或执行任务的实现代码
Dec 03 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
php数组函数序列之array_intersect() 返回两个或多个数组的交集数组
2011/11/10 PHP
PHP的反射类ReflectionClass、ReflectionMethod使用实例
2014/08/05 PHP
PHP常用技术文之文件操作和目录操作总结
2014/09/27 PHP
浅析ThinkPHP缓存之快速缓存(F方法)和动态缓存(S方法)(日常整理)
2015/10/26 PHP
laravel 实现根据字段不同值做不同查询
2019/10/23 PHP
关于js数组去重的问题小结
2014/01/24 Javascript
同一个网页中实现多个JavaScript特效的方法
2015/02/02 Javascript
通过实例理解javascript中没有函数重载的概念
2015/06/03 Javascript
详解javascript高级定时器
2015/12/31 Javascript
Bootstrap入门教程一Hello Bootstrap初识
2017/03/02 Javascript
详解Vue组件之间的数据通信实例
2017/06/17 Javascript
使用Webpack提高Vue.js应用的方式汇总(四种)
2017/07/10 Javascript
vue组件 $children,$refs,$parent的使用详解
2017/07/31 Javascript
详解升级react-router 4 踩坑指南
2017/08/14 Javascript
vue slots 组件的组合/分发实例
2018/09/06 Javascript
对angularjs框架下controller间的传值方法详解
2018/10/08 Javascript
[43:14]Liquid vs Optic 2018国际邀请赛淘汰赛BO3 第二场 8.21
2018/08/22 DOTA
跟老齐学Python之不要红头文件(1)
2014/09/28 Python
Python元组拆包和具名元组解析实例详解
2018/03/26 Python
浅析PyTorch中nn.Linear的使用
2019/08/18 Python
python实现飞机大战小游戏
2019/11/08 Python
利用Python脚本实现自动刷网课
2020/02/03 Python
基于pytorch中的Sequential用法说明
2020/06/24 Python
详解如何在css中引入自定义字体(font-face)
2018/05/17 HTML / CSS
HTML5打开本地app应用的方法
2016/03/31 HTML / CSS
New Balance波兰官方商城:始于1906年,百年慢跑品牌
2017/08/15 全球购物
澳大利亚拥有最好的家具和家居用品在线目的地:Nestz
2019/02/23 全球购物
路政管理毕业自荐书范文
2014/02/10 职场文书
《狼和小羊》教学反思
2014/04/20 职场文书
学校领导班子群众路线整改措施
2014/09/16 职场文书
教师学习八项规定六项禁令思想汇报
2014/09/27 职场文书
公务员年度考核个人总结
2015/02/12 职场文书
2015年乡镇妇联工作总结
2015/05/19 职场文书
学习党史心得体会2016
2016/01/23 职场文书
导游词之宿迁乾隆行宫
2019/10/15 职场文书
浅谈css实现背景颜色半透明的两种方法
2021/12/06 HTML / CSS