【问题标题】:Cannot serialize datetime as JSON from Cherrypy无法从 Cherrypy 将日期时间序列化为 JSON
【发布时间】:2011-12-22 02:28:41
【问题描述】:

我正在尝试发送记录列表以响应 Ajax 查询。这很好用,除非当我的进程失败并出现错误 datetime.date(2011, 11, 1) is not JSON serializable 时结果包含日期时间字段。

我试图将我在此处找到的非常 similar question 的答案与 CherryPy documentation 中的说明结合起来使用自定义 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 编码的默认处理程序来完成,但我不确定如何调用那个方法)。

【问题讨论】:

    标签: python json datetime cherrypy


    【解决方案1】:

    对于自定义 json_handler 实现,请参阅 Pierre 的出色回答。但是,每次使用工具时都指定@cherrypy.tools.json_out(handler=json_handler)有点麻烦,所以作为jsontools.json_out source code points out,最好使用这个:

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

    此外,您可以使用 _cp_config 在类级别启用工具:

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

    【讨论】:

      【解决方案2】:

      我遇到了同样的问题(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):
               ...
      

      【讨论】:

      【解决方案3】:

      我在类似的情况下做下一个:

      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)
      

      【讨论】:

      • 谢谢,我把我的编码器改写成一个类,复制你的。但是,我没有调用 json.dumps() 而是使用 CherryPy 的 json 工具。这些工具可以配置一个自定义处理程序进行编码,但它们需要一个函数,而不是类或实例。
      • 我现在已经删除了用于 JSON 编码的 CherryPy 工具,并直接调用 simplejson.dumps()。使用此配置,您向我展示的编码器可以正常工作。谢谢!
      • 这是 v3 特定的吗?我无法让它在 v2.7.5 上运行。我遵循的步骤是相同的​​。如果我想 jsonify 我的模型列表(比如 A),这不起作用,其中 A 的属性是日期时间类型。我相信我们只想检索一个模型的 JSON,这样可以正常工作
      • DateEncoder::default() 函数如何调用最后一个 return 语句?
      猜你喜欢
      • 1970-01-01
      • 2013-09-22
      • 1970-01-01
      • 1970-01-01
      • 2020-06-07
      • 1970-01-01
      • 2012-08-14
      • 1970-01-01
      相关资源
      最近更新 更多