json实现不支持转换数据类型得转换
当我们用json模块的dumps把一种json模块不支持的数据类型进行转换成json字符串的时候,会报错
TypeError: Object of type 'datetime' is not JSON serializable
“datetime 类型的对象不能被json解析”
但是现在的业务逻辑是我们非要让他能够解析,这时候看他的源码。
先进入到dumps的源码之中
def dumps(obj, *, skipkeys=False, ensure_ascii=True, check_circular=True,
allow_nan=True, cls=None, indent=None, separators=None,
default=None, sort_keys=False, **kw):
看见里面有一个 cls = None,这时候先不要看cls是什么,然后往下看,找到了一个
if cls is None:
cls = JSONEncoder
点进去 JSONEncoder 看他的源码,
def default(self, o):
"""Implement this method in a subclass such that it returns
a serializable object for ``o``, or calls the base implementation
(to raise a ``TypeError``).
For example, to support arbitrary iterators, you could
implement default like this::
def default(self, o):
try:
iterable = iter(o)
except TypeError:
pass
else:
return list(iterable)
# Let the base class default method raise the TypeError
return JSONEncoder.default(self, o)
"""
raise TypeError("Object of type '%s' is not JSON serializable" %
o.__class__.__name__)
看到了这句抛出异常,和我们的报错是一样的,所以,我们这时候可以通过重写这个 JSONEncoder类的default方法,来实现我们要的业务逻辑。
class MyJsonClass(json.JSONEncoder):
def default(self, o):
if isinstance(o,datetime): # 如果o不是json默认能够序列化 你就在该方法内给他处理成json能够转的类型
return o.strftime('%Y-%m-%d')
else:
super().default(self,o)
比如我们要dumps的对象是一个datetime类型的数据,那么这里的isinstance第二个参数就写这个,判断来的对象是不是他的子类,是的话,就手动给他转换了,再返回,当然不是这种类型的时候要继续使用之前的功能,所以调用父类的default方法。
d = {'ctime':datetime.today()}
print(json.dumps(d,cls=MyJsonClass))
这时候在这里面写一个cls=MyJsonClass,就可以了,再看下去源码就是讲json是怎么序列化的了。
JsonResponse
Django有一个简单的方法,不需要我们去导入json模块,然后序列化了,
先导入以下模块
from django.http import JsonResponse
然后再调用就可以了
l = [1,2,3,4,5,5,6]
return JsonResponse(user,json_dumps_params={'ensure_ascii':False})
json_dumps_params是什么?进JsonResponse的源码看一下。
class JsonResponse(HttpResponse):
def __init__(self, data, encoder=DjangoJSONEncoder, safe=True,
json_dumps_params=None, **kwargs):
if safe and not isinstance(data, dict):
raise TypeError(
'In order to allow non-dict objects to be serialized set the '
'safe parameter to False.'
)
if json_dumps_params is None:
json_dumps_params = {}
kwargs.setdefault('content_type', 'application/json')
data = json.dumps(data, cls=encoder, **json_dumps_params)
super(JsonResponse, self).__init__(content=data, **kwargs)
Django叫我们不要导入json模块,用他的JsonResponse,而他自己
JsonResponse实现的方法却依然是基于json模块的,**json_dumps_params就是参数咯,所以我们只需要像上面那样写,带一个字典,它会把它打散成关键字参数,这时候就可以写入 ensure_ascii':False 了,他的作用是不让中文字符直接被转码成字节了。
现在进行一个操作:
l = [1,2,3,4,5,5,6]
return JsonResponse(l)
结果却报错了
错误信息
TypeError at /index/
In order to allow non-dict objects to be serialized set the safe parameter to False.
"为了允许序列化非dict对象,请将安全参数设置为False。"
那我们就去设置就好了
l = [1,2,3,4,5,5,6]
return JsonResponse(l,safe=False)
这时候就不会报错了。
总结
这两者都是django中后台返回给前台数据的方法,而且走的都是http协议
区别
HttpResponse需要前后台进行序列化和反序列化,JasonResponse把序列化和反序列化封装起来,传入可序列化字符串在前台就能收到对应数据.
后端
return HttpResponse(json.dumps(对象))
return JasonResponse(对象)
前端
js反序列化 res=JSON.parse(data);
序列化 JSON.stringify(res)
JasonResponse 直接返回的值就是对应的数据类型,不需要过多操作,字典还可以进行对象点方法
解决编码问题:
return JsonResponse(data,json_dumps_params={'ensure_ascii':False})
JasonResponse默认支持序列化字典,如果想要序列化其他类型(json能够支持的类型),只需要将safe参数有默认的True改为False