Невозможно сериализовать дату и время как JSON из Cherrypy - PullRequest
2 голосов
/ 04 ноября 2011

Я пытаюсь отправить список записей в ответ на запрос 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 ]

9 голосов
/ 06 февраля 2013

У меня возникла та же проблема (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):
         ...
9 голосов
/ 04 ноября 2011

Я делаю следующее в аналогичном случае:

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)
1 голос
/ 06 декабря 2015

О пользовательской реализации json_handler см. Отличный ответ Пьера.Однако указывать @cherrypy.tools.json_out(handler=json_handler) каждый раз, когда вы используете инструмент, немного громоздко, так как исходный код jsontools.json_out указывает , лучше использовать это:Вы можете включить инструменты на уровне класса, используя _cp_config:

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