我有一个基本的字典如下:

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。


当前回答

如果在视图中使用结果,请确保返回正确的响应。根据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

其他回答

我的解决方案(我认为不那么冗长):

def default(o):
    if type(o) is datetime.date or type(o) is datetime.datetime:
        return o.isoformat()

def jsondumps(o):
    return json.dumps(o, default=default)

然后使用jsondumps而不是json.dumps。它将打印:

>>> jsondumps({'today': datetime.date.today()})
'{"today": "2013-07-30"}'

如果你想,以后你可以添加其他特殊情况,通过一个简单的默认方法。例子:

def default(o):
    if type(o) is datetime.date or type(o) is datetime.datetime:
        return o.isoformat()
    if type(o) is decimal.Decimal:
        return float(o)

最简单的方法是将字典中datetime格式的部分更改为isoformat。这个值实际上是一个isoformat的字符串,json可以接受。

v_dict = version.dict()
v_dict['created_at'] = v_dict['created_at'].isoformat()

通常有几种方法来序列化日期时间,比如:

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为您做的。它也很容易为人类编辑。

免责声明:这是我做的。因为我也有同样的问题。

我在外部化django模型对象转储为JSON时也遇到了同样的问题。 以下是解决方法。

def externalize(model_obj):
  keys = model_obj._meta.get_all_field_names() 
  data = {}
  for key in keys:
    if key == 'date_time':
      date_time_obj = getattr(model_obj, key)
      data[key] = date_time_obj.strftime("%A %d. %B %Y")
    else:
      data[key] = getattr(model_obj, key)
  return data

对于不需要或不想使用pymongo库的其他人。你可以用这个小片段轻松实现datetime JSON转换:

def default(obj):
    """Default JSON serializer."""
    import calendar, datetime

    if isinstance(obj, datetime.datetime):
        if obj.utcoffset() is not None:
            obj = obj - obj.utcoffset()
        millis = int(
            calendar.timegm(obj.timetuple()) * 1000 +
            obj.microsecond / 1000
        )
        return millis
    raise TypeError('Not sure how to serialize %s' % (obj,))

然后像这样使用它:

import datetime, json
print json.dumps(datetime.datetime.now(), default=default)

输出:

'1365091796124'