Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Added JSON Support and started working on jQuery docs

  • Loading branch information...
commit 6e2be6a0b3aba4ab49cf3ed1a10ac13c6b771aba 1 parent c64a4e0
@mitsuhiko authored
View
59 docs/api.rst
@@ -56,12 +56,15 @@ Incoming Request Data
.. attribute:: stream
- If the incoming form data was not encoded with a known encoding (for
- example it was transmitted as JSON) the data is stored unmodified in
- this stream for consumption. For example to read the incoming
- request data as JSON, one can do the following::
+ If the incoming form data was not encoded with a known mimetype
+ the data is stored unmodified in this stream for consumption. Most
+ of the time it is a better idea to use :attr:`data` which will give
+ you that data as a string. The stream only returns the data once.
+
+ .. attribute:: data
- json_body = simplejson.load(request.stream)
+ Contains the incoming request data as string in case it came with
+ a mimetype Flask does not handle.
.. attribute:: files
@@ -106,6 +109,20 @@ Incoming Request Data
`root_url` ``http://www.example.com/myapplication/``
============= ======================================================
+ .. attribute:: is_xhr
+
+ `True` if the request was triggered via a JavaScript
+ `XMLHttpRequest`. This only works with libraries that support the
+ ``X-Requested-With`` header and set it to `XMLHttpRequest`.
+ Libraries that do that are prototype, jQuery and Mochikit and
+ probably some more.
+
+ .. attribute:: json
+
+ Contains the parsed body of the JSON request if the mimetype of
+ the incoming data was `application/json`. This requires Python 2.6
+ or an installed version of simplejson.
+
Response Objects
----------------
@@ -201,6 +218,38 @@ Message Flashing
.. autofunction:: get_flashed_messages
+Returning JSON
+--------------
+
+.. autofunction:: jsonify
+
+.. data:: json
+
+ If JSON support is picked up, this will be the module that Flask is
+ using to parse and serialize JSON. So instead of doing this yourself::
+
+ try:
+ import simplejson as json
+ except ImportError:
+ import json
+
+ You can instead just do this::
+
+ from flask import json
+
+ For usage examples, read the :mod:`json` documentation.
+
+ The :func:`~json.dumps` function of this json module is also available
+ as filter called ``|tojson`` in Jinja2. Note that inside `script`
+ tags no escaping must take place, so make sure to disable escaping
+ with ``|safe`` if you intend to use it inside `script` tags:
+
+ .. sourcecode:: html+jinja
+
+ <script type=text/javascript>
+ doSomethingWith({{ user.username|tojson|safe }});
+ </script>
+
Template Rendering
------------------
View
1  docs/patterns/index.rst
@@ -19,3 +19,4 @@ end of the request, the database connection is closed again.
wtforms
templateinheritance
flashing
+ jquery
View
59 docs/patterns/jquery.rst
@@ -0,0 +1,59 @@
+AJAX With jQuery
+================
+
+`jQuery`_ is a small JavaScript library commonly used to simplify working
+with the DOM and JavaScript in general. It is the perfect tool to make
+web applications more dynamic by exchanging JSON between server and
+client.
+
+.. _jQuery: http://jquery.com/
+
+Loading jQuery
+--------------
+
+In order to use jQuery, you have to download it first and place it in the
+static folder of your application and then ensure it's loaded. Ideally
+you have a layout template that is used for all pages where you just have
+to add two script statements to your `head` section. One for jQuery, and
+one for your own script (called `app.js` here):
+
+.. sourcecode:: html
+
+ <script type=text/javascript src="{{
+ url_for('static', filename='jquery.js') }}"></script>
+ <script type=text/javascript src="{{
+ url_for('static', filename='app.js') }}"></script>
+
+Where is My Site?
+-----------------
+
+Do you know where your application is? If you are developing the answer
+is quite simple: it's on localhost port something and directly on the root
+of that server. But what if you later decide to move your application to
+a different location? For example to ``http://example.com/myapp``? On
+the server side this never was a problem because we were using the handy
+:func:`~flask.url_for` function that did could answer that question for
+us, but if we are using jQuery we should better not hardcode the path to
+the application but make that dynamic, so how can we do that?
+
+A simple method would be to add a script tag to our page that sets a
+global variable to the prefix to the root of the application. Something
+like this:
+
+.. sourcecode:: html+jinja
+
+ <script type=text/javascript>
+ $SCRIPT_ROOT = {{ request.script_root|tojson|safe }};
+ </script>
+
+The ``|safe`` is necessary so that Jinja does not escape the JSON encoded
+string with HTML rules. Usually this would be necessary, but we are
+inside a `script` block here where different rules apply.
+
+.. admonition:: Information for Pros
+
+ In HTML the `script` tag is declared `CDATA` which means that entities
+ will not be parsed. Everything until ``</script>`` is handled as script.
+ This also means that there must never be any ``</`` between the script
+ tags. ``|tojson`` is kindly enough to do the right thing here and
+ escape backslashes for you.
View
29 examples/jqueryexample/jqueryexample.py
@@ -0,0 +1,29 @@
+# -*- coding: utf-8 -*-
+"""
+ jQuery Example
+ ~~~~~~~~~~~~~~
+
+ A simple application that shows how Flask and jQuery get along.
+
+ :copyright: (c) 2010 by Armin Ronacher.
+ :license: BSD, see LICENSE for more details.
+"""
+from flask import Flask, jsonify, render_template, request
+app = Flask(__name__)
+
+
+@app.route('/_add_numbers')
+def add_numbers():
+ """Add two numbers server side, ridiculous but well..."""
+ a = request.args.get('a', 0, type=int)
+ b = request.args.get('b', 0, type=int)
+ return jsonify(result=a + b)
+
+
+@app.route('/')
+def index():
+ return render_template('index.html')
+
+
+if __name__ == '__main__':
+ app.run()
View
25 examples/jqueryexample/templates/index.html
@@ -0,0 +1,25 @@
+<!doctype html>
+<title>jQuery Example</title>
+<script type=text/javascript
+ src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
+<script type=text/javascript src="{{ url_for('static', filename='app.js')
+ }}"></script>
+<script type=text/javascript>
+ var $SCRIPT_ROOT = {{ request.script_root|tojson|safe }};
+
+ $(function() {
+ $('a#calculate').bind('click', function() {
+ $.getJSON($SCRIPT_ROOT + '/_add_numbers', {
+ a: $('input[name="a"]').val(),
+ b: $('input[name="b"]').val()
+ }, function(data) {
+ $("#result").text(data.result);
+ });
+ });
+ });
+</script>
+<h1>jQuery Example</h1>
+<p><input type=text size=5 name=a> +
+ <input type=text size=5 name=b> =
+ <span id=result>?</span>
+<p><a href=# id=calculate>calculate server side</a>
View
58 flask.py
@@ -15,11 +15,23 @@
from jinja2 import Environment, PackageLoader, FileSystemLoader
from werkzeug import Request as RequestBase, Response as ResponseBase, \
- LocalStack, LocalProxy, create_environ, SharedDataMiddleware
+ LocalStack, LocalProxy, create_environ, SharedDataMiddleware, \
+ cached_property
from werkzeug.routing import Map, Rule
from werkzeug.exceptions import HTTPException
from werkzeug.contrib.securecookie import SecureCookie
+# try to load the best simplejson implementation available. If JSON
+# is not installed, we add a failing class.
+json_available = True
+try:
+ import simplejson as json
+except ImportError:
+ try:
+ import json
+ except ImportError:
+ json_available = False
+
# utilities we import from Werkzeug and Jinja2 that are unused
# in the module but are exported as public interface.
from werkzeug import abort, redirect
@@ -49,6 +61,16 @@ def __init__(self, environ):
self.endpoint = None
self.view_args = None
+ @cached_property
+ def json(self):
+ """If the mimetype is `application/json` this will contain the
+ parsed JSON data.
+ """
+ if not json_available:
+ raise AttributeError('simplejson not available')
+ if self.mimetype == 'application/json':
+ return json.loads(self.data)
+
class Response(ResponseBase):
"""The response object that is used by default in flask. Works like the
@@ -81,7 +103,6 @@ def _fail(self, *args, **kwargs):
del _fail
-
class _RequestContext(object):
"""The request context contains all request relevant information. It is
created at the beginning of the request and pushed to the
@@ -133,6 +154,8 @@ def get_template_attribute(template_name, attribute):
hello = get_template_attribute('_foo.html', 'hello')
return hello('World')
+ .. versionadded:: 0.2
+
:param template_name: the name of the template
:param attribute: the name of the variable of macro to acccess
"""
@@ -162,6 +185,35 @@ def get_flashed_messages():
return flashes
+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.
+
+ .. versionadded:: 0.2
+ """
+ return current_app.response_class(json.dumps(dict(*args, **kwargs),
+ indent=None if request.is_xhr else 2), mimetype='application/json')
+
+
def render_template(template_name, **context):
"""Renders a template from the template folder with the given
context.
@@ -326,6 +378,8 @@ def __init__(self, package_name):
url_for=url_for,
get_flashed_messages=get_flashed_messages
)
+ if json_available:
+ self.jinja_env.filters['tojson'] = json.dumps
def create_jinja_loader(self):
"""Creates the Jinja loader. By default just a package loader for
View
32 tests/flask_tests.py
@@ -32,7 +32,7 @@ def meh():
assert meh() == 'http://localhost/meh'
-class BasicFunctionality(unittest.TestCase):
+class BasicFunctionalityTestCase(unittest.TestCase):
def test_request_dispatching(self):
app = flask.Flask(__name__)
@@ -167,7 +167,35 @@ def test_static_files(self):
== '/static/index.html'
-class Templating(unittest.TestCase):
+class JSONTestCase(unittest.TestCase):
+
+ def test_jsonify(self):
+ d = dict(a=23, b=42, c=[1, 2, 3])
+ app = flask.Flask(__name__)
+ @app.route('/kw')
+ def return_kwargs():
+ return flask.jsonify(**d)
+ @app.route('/dict')
+ def return_dict():
+ return flask.jsonify(d)
+ c = app.test_client()
+ for url in '/kw', '/dict':
+ rv = c.get(url)
+ assert rv.mimetype == 'application/json'
+ assert flask.json.loads(rv.data) == d
+
+ def test_json_attr(self):
+ app = flask.Flask(__name__)
+ @app.route('/add', methods=['POST'])
+ def add():
+ return unicode(flask.request.json['a'] + flask.request.json['b'])
+ c = app.test_client()
+ rv = c.post('/add', data=flask.json.dumps({'a': 1, 'b': 2}),
+ content_type='application/json')
+ assert rv.data == '3'
+
+
+class TemplatingTestCase(unittest.TestCase):
def test_context_processing(self):
app = flask.Flask(__name__)
Please sign in to comment.
Something went wrong with that request. Please try again.