无法将Cherrypy中的日期时间序列化为JSON

3 投票
3 回答
5776 浏览
提问于 2025-04-17 05:38

我正在尝试在响应一个Ajax请求时发送一系列记录。这个过程运行得很好,除非结果中包含一个日期时间字段,这时我就会遇到错误 datetime.date(2011, 11, 1) is not JSON serializable

我试图把我在一个非常类似问题中找到的答案和CherryPy文档中的说明结合起来,使用一个自定义的json_out编码器,但我不太明白这个函数应该是什么样的。 我写的函数是:

 def json_encoder(thing):

      if hasattr(thing, 'isoformat'):
           return thing.isoformat()
      else:
           return str(thing)

现在,任何使用json_out(即使输出中没有日期时间)都会给我带来错误 TypeError: json_encoder() takes exactly 1 argument (0 given)。但是如果编码器不接受参数,那它是怎么接收要编码的对象的呢?

(另外,我觉得我用str(thing)作为默认的编码方法是错的,这应该通过调用json编码的默认处理程序来完成,但我不太确定该怎么调用那个方法)。

3 个回答

2

关于自定义的 json_handler 实现,可以参考皮埃尔的精彩回答。不过,每次使用这个工具都要写 @cherrypy.tools.json_out(handler=json_handler),这有点麻烦。因此,正如 jsontools.json_out 的源代码所指出的,更好的做法是使用下面的方式:

cherrypy.config['tools.json_out.handler'] = json_handler

另外,你还可以通过 _cp_config 在类级别启用工具:

class Example
_cp_config = {
  'tools.json_out.on': True
}
12

我遇到了同样的问题(Python 3.2,Cherrypy 3.2.2),我用下面的代码解决了它:

import cherrypy
import json
import datetime
class _JSONEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, datetime.date):
            return obj.isoformat()
        return super().default(obj)
    def iterencode(self, value):
        # Adapted from cherrypy/_cpcompat.py
        for chunk in super().iterencode(value):
            yield chunk.encode("utf-8")

json_encoder = _JSONEncoder()

def json_handler(*args, **kwargs):
    # Adapted from cherrypy/lib/jsontools.py
    value = cherrypy.serving.request._json_inner_handler(*args, **kwargs)
    return json_encoder.iterencode(value)

然后你可以使用 Cherrypy 的 json_out 装饰器:

class Root:
     @cherrypy.expose
     @cherrypy.tools.json_out(handler=json_handler)
     def default(self, *args, **kwargs):
         ...
10

在类似的情况下,我会这样做:

class DecimalEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, Decimal):
            return float(obj)
        return json.JSONEncoder.default(self, obj)

然后在调用的时候:

json.dumps(my_variable, cls=DecimalEncoder)

所以在你的情况下应该是这样的:

class DateEncoder(json.JSONEncoder):
    def default(self, obj):
        if hasattr(obj, 'isoformat'):
            return obj.isoformat()
        else:
            return str(obj)
        return json.JSONEncoder.default(self, obj)


json.dumps(my_variable, cls=DateEncoder)

撰写回答