我有一个基本的字典如下:
sample = {}
sample['title'] = "String"
sample['somedate'] = somedatetimehere
当我尝试做jsonify(sample)时,我得到:
TypeError: datetime.datetime(2012, 8, 8, 21, 46, 24, 862000) is not JSON serializable
我该怎么做才能使我的字典样本克服上面的错误呢?
注意:虽然它可能不相关,字典是从mongodb的记录检索中生成的,当我打印出str(sample['somedate'])时,输出是2012-08-08 21:46:24.862000。
通常有几种方法来序列化日期时间,比如:
ISO字符串,短,可以包含时区信息,例如@jgbarah的答案
时间戳(时区数据丢失),例如@JayTaylor的答案
属性字典(包括时区)。
如果您同意最后一种方法,json_tricks包将处理日期、时间和日期时间(包括时区)。
from datetime import datetime
from json_tricks import dumps
foo = {'title': 'String', 'datetime': datetime(2012, 8, 8, 21, 46, 24, 862000)}
dumps(foo)
这使:
{"title": "String", "datetime": {"__datetime__": null, "year": 2012, "month": 8, "day": 8, "hour": 21, "minute": 46, "second": 24, "microsecond": 862000}}
所以你要做的就是
`pip install json_tricks`
然后导入从json_tricks而不是json。
不将其存储为单个字符串、int型或float型的优势体现在解码时:如果你遇到的只是字符串,特别是int型或float型,你需要了解一些关于数据的信息,以知道它是否是一个datetime。作为dict,您可以存储元数据,以便自动解码,这就是json_tricks为您做的。它也很容易为人类编辑。
免责声明:这是我做的。因为我也有同样的问题。
您应该在.datetime.now()方法上应用.strftime()方法,使其成为一个可序列化的方法。
这里有一个例子:
from datetime import datetime
time_dict = {'time': datetime.now().strftime('%Y-%m-%dT%H:%M:%S')}
sample_dict = {'a': 1, 'b': 2}
sample_dict.update(time_dict)
sample_dict
输出:
Out[0]: {'a': 1, 'b': 2, 'time': '2017-10-31T15:16:30'}
(更新):
在Python3.7及以后版本中,你可以简单地使用.isoformat()方法:
from datetime import datetime
datetime.now().isoformat()
其实很简单。
如果您需要经常序列化日期,那么可以将它们作为字符串使用。如果需要,您可以轻松地将它们转换回datetime对象。
如果您主要需要作为datetime对象工作,那么在序列化之前将它们转换为字符串。
import json, datetime
date = str(datetime.datetime.now())
print(json.dumps(date))
"2018-12-01 15:44:34.409085"
print(type(date))
<class 'str'>
datetime_obj = datetime.datetime.strptime(date, '%Y-%m-%d %H:%M:%S.%f')
print(datetime_obj)
2018-12-01 15:44:34.409085
print(type(datetime_obj))
<class 'datetime.datetime'>
如您所见,两种情况下的输出是相同的。只是类型不同。
如果您正在使用python3.7,那么最好的解决方案是使用
datetime.isoformat()和
datetime.fromisoformat ();他们与天真的和
感知datetime对象:
#!/usr/bin/env python3.7
from datetime import datetime
from datetime import timezone
from datetime import timedelta
import json
def default(obj):
if isinstance(obj, datetime):
return { '_isoformat': obj.isoformat() }
raise TypeError('...')
def object_hook(obj):
_isoformat = obj.get('_isoformat')
if _isoformat is not None:
return datetime.fromisoformat(_isoformat)
return obj
if __name__ == '__main__':
#d = { 'now': datetime(2000, 1, 1) }
d = { 'now': datetime(2000, 1, 1, tzinfo=timezone(timedelta(hours=-8))) }
s = json.dumps(d, default=default)
print(s)
print(d == json.loads(s, object_hook=object_hook))
输出:
{"now": {"_isoformat": "2000-01-01T00:00:00-08:00"}}
True
如果您使用的是python3.6或以下版本,并且您只关心时间值(不是
),然后您可以使用datetime.timestamp()和
datetime.fromtimestamp()而不是;
如果您使用的是python3.6或以下版本,并且您确实关心时区,那么
你可以通过datetime获取。Tzinfo,但是您必须序列化这个字段
自己;类中添加另一个字段_tzinfo是最简单的方法
序列化的对象;
最后,要注意所有这些例子的精确性;
如果在视图中使用结果,请确保返回正确的响应。根据API, jsonify执行以下操作:
使用给定参数的JSON表示创建一个Response
用一个application/json mimetype。
使用json模拟此行为。转储您必须添加几行额外的代码。
response = make_response(dumps(sample, cls=CustomEncoder))
response.headers['Content-Type'] = 'application/json'
response.headers['mimetype'] = 'application/json'
return response
您还应该返回一个dict以完全复制jsonify的响应。整个文件是这样的
from flask import make_response
from json import JSONEncoder, dumps
class CustomEncoder(JSONEncoder):
def default(self, obj):
if set(['quantize', 'year']).intersection(dir(obj)):
return str(obj)
elif hasattr(obj, 'next'):
return list(obj)
return JSONEncoder.default(self, obj)
@app.route('/get_reps/', methods=['GET'])
def get_reps():
sample = ['some text', <datetime object>, 123]
response = make_response(dumps({'result': sample}, cls=CustomEncoder))
response.headers['Content-Type'] = 'application/json'
response.headers['mimetype'] = 'application/json'
return response