mirror of https://github.com/mitsuhiko/flask.git
Armin Ronacher
12 years ago
9 changed files with 224 additions and 81 deletions
@ -0,0 +1,146 @@
|
||||
# -*- coding: utf-8 -*- |
||||
""" |
||||
flask.jsonimpl |
||||
~~~~~~~~~~~~~~ |
||||
|
||||
Implementation helpers for the JSON support in Flask. |
||||
|
||||
:copyright: (c) 2012 by Armin Ronacher. |
||||
:license: BSD, see LICENSE for more details. |
||||
""" |
||||
from datetime import datetime |
||||
from .globals import current_app, request |
||||
|
||||
from werkzeug.http import http_date |
||||
|
||||
# Use the same json implementation as itsdangerous on which we |
||||
# depend anyways. |
||||
from itsdangerous import simplejson as _json |
||||
|
||||
|
||||
# figure out if simplejson escapes slashes. This behavior was changed |
||||
# from one version to another without reason. |
||||
_slash_escape = '\\/' not in _json.dumps('/') |
||||
|
||||
|
||||
__all__ = ['dump', 'dumps', 'load', 'loads', 'htmlsafe_dump', |
||||
'htmlsafe_dumps', 'JSONDecoder', 'JSONEncoder', |
||||
'jsonify'] |
||||
|
||||
|
||||
class JSONEncoder(_json.JSONEncoder): |
||||
"""The default Flask JSON encoder. This one extends the default simplejson |
||||
encoder by also supporting ``datetime`` objects as well as ``Markup`` |
||||
objects which are serialized as RFC 822 datetime strings (same as the HTTP |
||||
date format). In order to support more data types override the |
||||
:meth:`default` method. |
||||
""" |
||||
|
||||
def default(self, o): |
||||
"""Implement this method in a subclass such that it returns a |
||||
serializable object for ``o``, or calls the base implementation (to |
||||
raise a ``TypeError``). |
||||
|
||||
For example, to support arbitrary iterators, you could implement |
||||
default like this:: |
||||
|
||||
def default(self, o): |
||||
try: |
||||
iterable = iter(o) |
||||
except TypeError: |
||||
pass |
||||
else: |
||||
return list(iterable) |
||||
return JSONEncoder.default(self, o) |
||||
""" |
||||
if isinstance(o, datetime): |
||||
return http_date(o) |
||||
if hasattr(o, '__html__'): |
||||
return unicode(o.__html__()) |
||||
return _json.JSONEncoder.default(self, o) |
||||
|
||||
|
||||
class JSONDecoder(_json.JSONDecoder): |
||||
"""The default JSON decoder. This one does not change the behavior from |
||||
the default simplejson encoder. Consult the :mod:`json` documentation |
||||
for more information. This decoder is not only used for the load |
||||
functions of this module but also :attr:`~flask.Request`. |
||||
""" |
||||
|
||||
|
||||
def dumps(obj, **kwargs): |
||||
"""Serialize ``obj`` to a JSON formatted ``str`` by using the application's |
||||
configured encoder (:attr:`~flask.Flask.json_encoder`). |
||||
""" |
||||
kwargs.setdefault('cls', current_app.json_encoder) |
||||
return _json.dumps(obj, **kwargs) |
||||
|
||||
|
||||
def dump(obj, fp, **kwargs): |
||||
"""Like :func:`dumps` but writes into a file object.""" |
||||
kwargs.setdefault('cls', current_app.json_encoder) |
||||
return _json.dump(obj, fp, **kwargs) |
||||
|
||||
|
||||
def loads(s, **kwargs): |
||||
"""Unserialize a JSON object from a string ``s`` by using the application's |
||||
configured decoder (:attr:`~flask.Flask.json_decoder`). |
||||
""" |
||||
kwargs.setdefault('cls', current_app.json_decoder) |
||||
return _json.loads(s, **kwargs) |
||||
|
||||
|
||||
def load(fp, **kwargs): |
||||
"""Like :func:`loads` but reads from a file object. |
||||
""" |
||||
kwargs.setdefault('cls', current_app.json_decoder) |
||||
return _json.load(fp, **kwargs) |
||||
|
||||
|
||||
def htmlsafe_dumps(obj, **kwargs): |
||||
"""Works exactly like :func:`dumps` but is safe for use in ``<script>`` |
||||
tags. It accepts the same arguments and returns a JSON string. Note that |
||||
this is available in templates through the ``|tojson`` filter but it will |
||||
have to be wrapped in ``|safe`` unless **true** XHTML is being used. |
||||
""" |
||||
rv = dumps(obj, **kwargs) |
||||
if _slash_escape: |
||||
rv = rv.replace('/', '\\/') |
||||
return rv.replace('<!', '<\\u0021') |
||||
|
||||
|
||||
def htmlsafe_dump(obj, fp, **kwargs): |
||||
"""Like :func:`htmlsafe_dumps` but writes into a file object.""" |
||||
fp.write(htmlsafe_dumps(obj, **kwargs)) |
||||
|
||||
|
||||
def jsonify(*args, **kwargs): |
||||
"""Creates a :class:`~flask.Response` with the JSON representation of |
||||
the given arguments with an `application/json` mimetype. The arguments |
||||
to this function are the same as to the :class:`dict` constructor. |
||||
|
||||
Example usage:: |
||||
|
||||
@app.route('/_get_current_user') |
||||
def get_current_user(): |
||||
return jsonify(username=g.user.username, |
||||
email=g.user.email, |
||||
id=g.user.id) |
||||
|
||||
This will send a JSON response like this to the browser:: |
||||
|
||||
{ |
||||
"username": "admin", |
||||
"email": "admin@localhost", |
||||
"id": 42 |
||||
} |
||||
|
||||
This requires Python 2.6 or an installed version of simplejson. For |
||||
security reasons only objects are supported toplevel. For more |
||||
information about this, have a look at :ref:`json-security`. |
||||
|
||||
.. versionadded:: 0.2 |
||||
""" |
||||
return current_app.response_class(dumps(dict(*args, **kwargs), |
||||
indent=None if request.is_xhr else 2), |
||||
mimetype='application/json') |
Loading…
Reference in new issue