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