问题
I'm attempting to send a list of records in response to an Ajax query. This works well unless the results include a datetime field when my process fails with the error datetime.date(2011, 11, 1) is not JSON serializable
.
I attempted to combine the answer I found to a very similar question here with instructions in the CherryPy documentation to use a custom json_out encoder, but it's not clear to me what signature that function must have. The function I wrote is:
def json_encoder(thing):
if hasattr(thing, 'isoformat'):
return thing.isoformat()
else:
return str(thing)
and now any use of json_out (even with no datetime in the output) gives me the error TypeError: json_encoder() takes exactly 1 argument (0 given)
. But if the encoder doesn't take an argument, how does it receive the object to encode?
(Also, I assume my use of str(thing)
as the default method of encoding is wrong and that this should be done with a call to whatever the default handler for json encoding is, but I'm not sure how to call that method).
回答1:
I do the next in a similar case:
class DecimalEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, Decimal):
return float(obj)
return json.JSONEncoder.default(self, obj)
and at the call:
json.dumps(my_variable, cls=DecimalEncoder)
So in your case it should be like:
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)
回答2:
I got the same problem (Python 3.2, Cherrypy 3.2.2) and I solved it with the following code:
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)
And then you can use the Cherrypy json_out
decorator:
class Root:
@cherrypy.expose
@cherrypy.tools.json_out(handler=json_handler)
def default(self, *args, **kwargs):
...
回答3:
For custom json_handler
implementation, see Pierre's excellent answer. However, specifying @cherrypy.tools.json_out(handler=json_handler)
every time you use the tool is a bit cumbersome, so as the jsontools.json_out source code points out, it's better to use this:
cherrypy.config['tools.json_out.handler'] = json_handler
Also, you can enable tools on class level using _cp_config:
class Example
_cp_config = {
'tools.json_out.on': True
}
来源:https://stackoverflow.com/questions/8011081/cannot-serialize-datetime-as-json-from-cherrypy