It would be neat to be able to control the serialization of arbitrary objects with jsonify. The dumps function allows you to pass a callable for this. I propose the addition of either an overridable method on the Flask class that is passed by jsonify, or a decorator for registering such a function. The "default default" could simply raise TypeError, the "default default" for the json module.
def json_defaults(self, obj):
if isinstance(obj, datetime):
… or …
if isinstance(obj, datetime):
Unlike the rejected pull-request, this should be thread-safe. As for direct use of the json module, one can simply pass the reference:
In a discussion on IRC, Armin expressed concern that this kind of adaption isn't very useful in practice, because it differs between requests what one wants serialized from an object. This problem can be solved by exploiting the fact that jsonify is request-bound, and the defaults function is able to read context-locals such as 'g'. It may not "feel" right but it is essentially what we need: a global state for the request.
data = dict(name=self.name, joined=self.created_at)
if g.user is self:
The gain is that we can simplify views and structure the code better by moving model-logic to models. We can avoid repeating ourselves — the serialization is recursive, we just reference a datetime object and a list of instances of the Post model. We don't lose anything because by default it will behave as before and regardless we can still pass standard types directly to jsonify.
If you [Armin] approve the idea and decide on an API, I'll try my hand at a patch if you like.
There might be a better name for 'json_defaults' BTW. Suggestions?
In the standard lib, it's called 'cls', which is not terribly descriptive. http://docs.python.org/library/json.html . Maybe 'json_cls', or 'json_dumper'? Those are both quite hideous as well though.
"To use a custom JSONEncoder subclass (e.g. one that overrides the default() method to serialize additional types), specify it with the cls kwarg; otherwise JSONEncoder is used."
+1 on this issue. datetime objects in particular don't serialize by default, which makes writing JSON API's with jsonify difficult, as this is a common data type in API's.
+1 to dag 's comment, as a simple answer we would only need to be able to pass a callable to the internal json.dumps call in the 'default' kwarg.
Unfortunately, the way jsonify is currently written, the args, *kwargs arguments to jsonify makes it impossible to specify any arguments to the internal json.dumps 'out of band' from your data. I'm not sure how to implement a way to pass in 'default', while at the same time keeping backwards compatibility and allowing 'default' as a key in your data. Perhaps a new json helper, or json oriented extension is needed?
I see a few of options here.
While (3) seems quite cool, it is a departure from standard json/simplejson practice, whereas (1) and (2) basically expose standard simplejson customization mechanisms to the user. How about a combination of (1) and (2), where you can specify a JSONEncoder class, or a default callback, or none of the above?
If either 1 or 2 were available, 3 could be implemented by the project or an extension.
Fix #220: adds a default JSONEncoder implementation to Flask.json_enc…
…oder_class, which users can override with their own implementation; makes jsonify use current_app.json_encoder_class as its encoder class.
Pull request #471 is a first draft of a solution based on option number 1.
By the way, there now seems to be a fair number of JSON handling functionality in flask/helpers.py; should they move to their own module at some point?
Overriding jsonify with a custom function that uses my own JSONEncoder is something most if not all of my Flask projects do. Definitely +1 on the issue. @app.json_default or similar would certainly look flask-like, but it I suppose it's not clear what would happen if you use it multiple times.
This has been implemented in master, where the attribute for the custom JSONEncoder is app.json_encoder. This ticket can safely be closed.