解决flask_restful无法对Decimal类型数据进行序列化问题
目录
在使用flask进行开发的时候发现 Decimal 类型的数据无法在作为 JSON 通过相应消息体序列化返回,出现 jsonschema.exceptions.ValidationError 错误:
jsonschema.exceptions.ValidationError: '1000.00' is not of type 'number'
在使用flask进行开发的时候发现 Decimal 类型的数据无法在作为 JSON 通过相应消息体序列化返回,出现 jsonschema.exceptions.ValidationError 错误:
jsonschema.exceptions.ValidationError: '1000.00' is not of type 'number'
研究 flask_restful/representations/json.py 代码发现问题出现在 json.dump()中
7 def output_json(data, code, headers=None):
8 """Makes a Flask response with a JSON encoded body"""
9
10 settings = current_app.config.get('RESTFUL_JSON', {})
11
...
21 dumped = dumps(data, **settings) + "\n"
通过下面实验也可以对问题得到验证。
>>> import json
>>> import decimal
>>> json.dumps(decimal.Decimal('99.99'))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/Cellar/python/3.6.5_1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/__init__.py", line 231, in dumps
return _default_encoder.encode(obj)
File "/usr/local/Cellar/python/3.6.5_1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/encoder.py", line 199, in encode
chunks = self.iterencode(o, _one_shot=True)
File "/usr/local/Cellar/python/3.6.5_1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/encoder.py", line 257, in iterencode
return _iterencode(o, 0)
File "/usr/local/Cellar/python/3.6.5_1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/encoder.py", line 180, in default
o.__class__.__name__)
TypeError: Object of type 'Decimal' is not JSON serializable
查看json.dumps()的文档知道可以通过参数 ‘cls’ 指定JSONEncoder进行序列化。
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)
Serialize ``obj`` to a JSON formatted ``str``.
To use a custom ``JSONEncoder`` subclass (e.g. one that overrides the
``.default()`` method to serialize additional types), specify it with
the ``cls`` kwarg; otherwise ``JSONEncoder`` is used.
结合flask_restful,可以自行定义从JSONEncoder继承下来的序列化类,通过在config中的’RESTFUL_JSON’进行定义。
3 import json
4 import decimal
...
9 class DecimalEncoder(json.JSONEncoder):
10 def default(self, obj):
11 if isinstance(obj, decimal.Decimal):
12 return float(obj)
13 return super(DecimalEncoder, self).default(obj)
14
15 class BaseConfig(object):
16 RESTFUL_JSON = {'cls':DecimalEncoder}