json 和 JsonResponse

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

posted @ 2019-11-09 15:26  Huise.J  阅读(377)  评论(0编辑  收藏  举报