forked from orbit-oss/flask
Added JSON Support and started working on jQuery docs
This commit is contained in:
parent
c64a4e0bef
commit
6e2be6a0b3
7 changed files with 254 additions and 9 deletions
59
docs/api.rst
59
docs/api.rst
|
|
@ -56,12 +56,15 @@ Incoming Request Data
|
||||||
|
|
||||||
.. attribute:: stream
|
.. attribute:: stream
|
||||||
|
|
||||||
If the incoming form data was not encoded with a known encoding (for
|
If the incoming form data was not encoded with a known mimetype
|
||||||
example it was transmitted as JSON) the data is stored unmodified in
|
the data is stored unmodified in this stream for consumption. Most
|
||||||
this stream for consumption. For example to read the incoming
|
of the time it is a better idea to use :attr:`data` which will give
|
||||||
request data as JSON, one can do the following::
|
you that data as a string. The stream only returns the data once.
|
||||||
|
|
||||||
json_body = simplejson.load(request.stream)
|
.. attribute:: data
|
||||||
|
|
||||||
|
Contains the incoming request data as string in case it came with
|
||||||
|
a mimetype Flask does not handle.
|
||||||
|
|
||||||
.. attribute:: files
|
.. attribute:: files
|
||||||
|
|
||||||
|
|
@ -106,6 +109,20 @@ Incoming Request Data
|
||||||
`root_url` ``http://www.example.com/myapplication/``
|
`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
|
Response Objects
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
|
|
@ -201,6 +218,38 @@ Message Flashing
|
||||||
|
|
||||||
.. autofunction:: get_flashed_messages
|
.. 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
|
Template Rendering
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,3 +19,4 @@ end of the request, the database connection is closed again.
|
||||||
wtforms
|
wtforms
|
||||||
templateinheritance
|
templateinheritance
|
||||||
flashing
|
flashing
|
||||||
|
jquery
|
||||||
|
|
|
||||||
59
docs/patterns/jquery.rst
Normal file
59
docs/patterns/jquery.rst
Normal file
|
|
@ -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.
|
||||||
29
examples/jqueryexample/jqueryexample.py
Normal file
29
examples/jqueryexample/jqueryexample.py
Normal file
|
|
@ -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()
|
||||||
25
examples/jqueryexample/templates/index.html
Normal file
25
examples/jqueryexample/templates/index.html
Normal file
|
|
@ -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>
|
||||||
58
flask.py
58
flask.py
|
|
@ -15,11 +15,23 @@ import sys
|
||||||
|
|
||||||
from jinja2 import Environment, PackageLoader, FileSystemLoader
|
from jinja2 import Environment, PackageLoader, FileSystemLoader
|
||||||
from werkzeug import Request as RequestBase, Response as ResponseBase, \
|
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.routing import Map, Rule
|
||||||
from werkzeug.exceptions import HTTPException
|
from werkzeug.exceptions import HTTPException
|
||||||
from werkzeug.contrib.securecookie import SecureCookie
|
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
|
# utilities we import from Werkzeug and Jinja2 that are unused
|
||||||
# in the module but are exported as public interface.
|
# in the module but are exported as public interface.
|
||||||
from werkzeug import abort, redirect
|
from werkzeug import abort, redirect
|
||||||
|
|
@ -49,6 +61,16 @@ class Request(RequestBase):
|
||||||
self.endpoint = None
|
self.endpoint = None
|
||||||
self.view_args = 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):
|
class Response(ResponseBase):
|
||||||
"""The response object that is used by default in flask. Works like the
|
"""The response object that is used by default in flask. Works like the
|
||||||
|
|
@ -81,7 +103,6 @@ class _NullSession(SecureCookie):
|
||||||
del _fail
|
del _fail
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class _RequestContext(object):
|
class _RequestContext(object):
|
||||||
"""The request context contains all request relevant information. It is
|
"""The request context contains all request relevant information. It is
|
||||||
created at the beginning of the request and pushed to the
|
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')
|
hello = get_template_attribute('_foo.html', 'hello')
|
||||||
return hello('World')
|
return hello('World')
|
||||||
|
|
||||||
|
.. versionadded:: 0.2
|
||||||
|
|
||||||
:param template_name: the name of the template
|
:param template_name: the name of the template
|
||||||
:param attribute: the name of the variable of macro to acccess
|
:param attribute: the name of the variable of macro to acccess
|
||||||
"""
|
"""
|
||||||
|
|
@ -162,6 +185,35 @@ def get_flashed_messages():
|
||||||
return flashes
|
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):
|
def render_template(template_name, **context):
|
||||||
"""Renders a template from the template folder with the given
|
"""Renders a template from the template folder with the given
|
||||||
context.
|
context.
|
||||||
|
|
@ -326,6 +378,8 @@ class Flask(object):
|
||||||
url_for=url_for,
|
url_for=url_for,
|
||||||
get_flashed_messages=get_flashed_messages
|
get_flashed_messages=get_flashed_messages
|
||||||
)
|
)
|
||||||
|
if json_available:
|
||||||
|
self.jinja_env.filters['tojson'] = json.dumps
|
||||||
|
|
||||||
def create_jinja_loader(self):
|
def create_jinja_loader(self):
|
||||||
"""Creates the Jinja loader. By default just a package loader for
|
"""Creates the Jinja loader. By default just a package loader for
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ class ContextTestCase(unittest.TestCase):
|
||||||
assert meh() == 'http://localhost/meh'
|
assert meh() == 'http://localhost/meh'
|
||||||
|
|
||||||
|
|
||||||
class BasicFunctionality(unittest.TestCase):
|
class BasicFunctionalityTestCase(unittest.TestCase):
|
||||||
|
|
||||||
def test_request_dispatching(self):
|
def test_request_dispatching(self):
|
||||||
app = flask.Flask(__name__)
|
app = flask.Flask(__name__)
|
||||||
|
|
@ -167,7 +167,35 @@ class BasicFunctionality(unittest.TestCase):
|
||||||
== '/static/index.html'
|
== '/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):
|
def test_context_processing(self):
|
||||||
app = flask.Flask(__name__)
|
app = flask.Flask(__name__)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue