在最初接触flask时,我也曾对jsonify这个函数产生过类似的疑问,既然标准模块json的dumps方法也可以将字典转成json格式的字符串,那么为什么还要弄出一个jsonify呢?直到我阅读了flask的源码,方解开心中的疑问。
先来看标准模块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):
json.dumps在对数据进行序列化时,只对部分类型的数据进行转化,这些数据类型包括
python | json |
---|---|
dict | object |
list, tuple | array |
str | string |
int, float | number |
True | true |
False | false |
None | null |
如果在dumps的过程中,遇到了其他类型的数据,就会报错,比如下面的程序
import json
import datetime
data = {
'name': 'python',
'time': datetime.datetime.now(),
'test': None
}
data_str = json.dumps(data)
print(data_str)
执行后报错内容为
TypeError: Object of type 'datetime' is not JSON serializable
对象的类型是datetime,不可进行json序列化。对于这种情况,我们可以自定义一个转换方式,dumps方法有一个参数cls,默认情况下,cls将被赋值成JSONEncoder 这个类来负责对数据进行转换,因此,我们只需要创建一个类来继承它,并重载它的default方法即可,default方法专门用来处理那些标准数据类型之外的数据(上表中的那些数据)。
修改后的程序如下
import json
import datetime
data = {
'name': 'python',
'time': datetime.datetime.now(),
'test': None
}
class MyJsonEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, datetime.datetime):
return obj.strftime("%Y-%m-%d %H:%M:%S")
return json.JSONEncoder.default(obj)
data_str = json.dumps(data, cls=MyJsonEncoder)
print(data_str)
jsonify里面所使用的json模块来自于第三方库itsdangerous, 这个模块提供了一系列方法将可信的数据传入不可信的环境。itsdangerous中的json也不是自己开发的,而是用了simplejson,据说比标准库json更快。
事情似乎水落石出了,但这不能解答本文的问题,jsonify与json.dumps的区别,本质上他们都是对数据进行序列化,他们都遵守json标准,区别在于,flask的jsonify提供了一个JSONEncoder用来解决标准json模块dumps不能转换的数据,JSONEncoder类定义如下
class JSONEncoder(_json.JSONEncoder):
def default(self, o):
if isinstance(o, datetime):
return http_date(o.utctimetuple())
if isinstance(o, date):
return http_date(o.timetuple())
if isinstance(o, uuid.UUID):
return str(o)
if dataclasses and dataclasses.is_dataclass(o):
return dataclasses.asdict(o)
if hasattr(o, "__html__"):
return text_type(o.__html__())
return _json.JSONEncoder.default(self, o)
在第一小节中,我自己实现了一个MyJsonEncoder,只对datetime数据类型做了转换处理,而flask提供的JSONEncoder则对很多种数据类型做了处理,因此更加安全,这就是他们之间的区别。
如果我们在flask应用中使用标准模块json,就必须自己提供JSONEncoder,才能应对非标准类型的数据,而使用jsonify就不需要操心这些事情了。
QQ交流群: 211426309