|
|
|
@ -159,14 +159,11 @@ Have another debugger in mind? See :ref:`working-with-debuggers`.
|
|
|
|
|
Routing |
|
|
|
|
------- |
|
|
|
|
|
|
|
|
|
Modern web applications have beautiful URLs. This helps people remember |
|
|
|
|
the URLs, which is especially handy for applications that are used from |
|
|
|
|
mobile devices with slower network connections. If the user can directly |
|
|
|
|
go to the desired page without having to hit the index page it is more |
|
|
|
|
likely they will like the page and come back next time. |
|
|
|
|
Modern web applications use meaningful URLs to help users. Users are more |
|
|
|
|
likely to like a page and come back if the page uses a meaningful URL they can |
|
|
|
|
remember and use to directly visit a page. |
|
|
|
|
|
|
|
|
|
As you have seen above, the :meth:`~flask.Flask.route` decorator is used to |
|
|
|
|
bind a function to a URL. Here are some basic examples:: |
|
|
|
|
Use the :meth:`~flask.Flask.route` decorator to bind a function to a URL. :: |
|
|
|
|
|
|
|
|
|
@app.route('/') |
|
|
|
|
def index(): |
|
|
|
@ -176,16 +173,16 @@ bind a function to a URL. Here are some basic examples::
|
|
|
|
|
def hello(): |
|
|
|
|
return 'Hello, World' |
|
|
|
|
|
|
|
|
|
But there is more to it! You can make certain parts of the URL dynamic and |
|
|
|
|
attach multiple rules to a function. |
|
|
|
|
You can do more! You can make parts of the URL dynamic and attach multiple |
|
|
|
|
rules to a function. |
|
|
|
|
|
|
|
|
|
Variable Rules |
|
|
|
|
`````````````` |
|
|
|
|
|
|
|
|
|
To add variable parts to a URL you can mark these special sections as |
|
|
|
|
``<variable_name>``. Such a part is then passed as a keyword argument to your |
|
|
|
|
function. Optionally a converter can be used by specifying a rule with |
|
|
|
|
``<converter:variable_name>``. Here are some nice examples:: |
|
|
|
|
You can add variable sections to a URL by marking sections with |
|
|
|
|
``<variable_name>``. Your function then receives the ``<variable_name>`` |
|
|
|
|
as a keyword argument. Optionally, you can use a converter to specify the type |
|
|
|
|
of the argument like ``<converter:variable_name>``. :: |
|
|
|
|
|
|
|
|
|
@app.route('/user/<username>') |
|
|
|
|
def show_user_profile(username): |
|
|
|
@ -197,22 +194,23 @@ function. Optionally a converter can be used by specifying a rule with
|
|
|
|
|
# show the post with the given id, the id is an integer |
|
|
|
|
return 'Post %d' % post_id |
|
|
|
|
|
|
|
|
|
The following converters exist: |
|
|
|
|
@app.route('/path/<path:subpath>') |
|
|
|
|
def show_subpath(subpath): |
|
|
|
|
# show the subpath after /path/ |
|
|
|
|
return 'Subpath %s' % subpath |
|
|
|
|
|
|
|
|
|
=========== =============================================== |
|
|
|
|
`string` accepts any text without a slash (the default) |
|
|
|
|
`int` accepts integers |
|
|
|
|
`float` like ``int`` but for floating point values |
|
|
|
|
`path` like the default but also accepts slashes |
|
|
|
|
`any` matches one of the items provided |
|
|
|
|
`uuid` accepts UUID strings |
|
|
|
|
=========== =============================================== |
|
|
|
|
Converter types: |
|
|
|
|
|
|
|
|
|
.. admonition:: Unique URLs / Redirection Behavior |
|
|
|
|
========== ========================================== |
|
|
|
|
``string`` (default) accepts any text without a slash |
|
|
|
|
``int`` accepts positive integers |
|
|
|
|
``float`` accepts positive floating point values |
|
|
|
|
``path`` like ``string`` but also accepts slashes |
|
|
|
|
``uuid`` accepts UUID strings |
|
|
|
|
========== ========================================== |
|
|
|
|
|
|
|
|
|
Flask's URL rules are based on Werkzeug's routing module. The idea |
|
|
|
|
behind that module is to ensure beautiful and unique URLs based on |
|
|
|
|
precedents laid down by Apache and earlier HTTP servers. |
|
|
|
|
Unique URLs / Redirection Behavior |
|
|
|
|
`````````````````````````````````` |
|
|
|
|
|
|
|
|
|
Take these two rules:: |
|
|
|
|
|
|
|
|
@ -224,148 +222,94 @@ The following converters exist:
|
|
|
|
|
def about(): |
|
|
|
|
return 'The about page' |
|
|
|
|
|
|
|
|
|
Though they look rather similar, they differ in their use of the trailing |
|
|
|
|
slash in the URL *definition*. In the first case, the canonical URL for the |
|
|
|
|
``projects`` endpoint has a trailing slash. In that sense, it is similar to |
|
|
|
|
a folder on a filesystem. Accessing it without a trailing slash will cause |
|
|
|
|
Flask to redirect to the canonical URL with the trailing slash. |
|
|
|
|
Though they look similar, they differ in their use of the trailing slash in |
|
|
|
|
the URL. In the first case, the canonical URL for the ``projects`` endpoint |
|
|
|
|
uses a trailing slash. It's similar to a folder in a file system; if you |
|
|
|
|
access the URL without a trailing slash, Flask redirects you to the |
|
|
|
|
canonical URL with the trailing slash. |
|
|
|
|
|
|
|
|
|
In the second case, however, the URL is defined without a trailing slash, |
|
|
|
|
rather like the pathname of a file on UNIX-like systems. Accessing the URL |
|
|
|
|
with a trailing slash will produce a 404 "Not Found" error. |
|
|
|
|
In the second case, however, the URL definition lacks a trailing slash, |
|
|
|
|
like the pathname of a file on UNIX-like systems. Accessing the URL with a |
|
|
|
|
trailing slash produces a 404 “Not Found” error. |
|
|
|
|
|
|
|
|
|
This behavior allows relative URLs to continue working even if the trailing |
|
|
|
|
slash is omitted, consistent with how Apache and other servers work. Also, |
|
|
|
|
the URLs will stay unique, which helps search engines avoid indexing the |
|
|
|
|
same page twice. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.. _url-building: |
|
|
|
|
|
|
|
|
|
URL Building |
|
|
|
|
```````````` |
|
|
|
|
|
|
|
|
|
If it can match URLs, can Flask also generate them? Of course it can. To |
|
|
|
|
build a URL to a specific function you can use the :func:`~flask.url_for` |
|
|
|
|
function. It accepts the name of the function as first argument and a number |
|
|
|
|
of keyword arguments, each corresponding to the variable part of the URL rule. |
|
|
|
|
Unknown variable parts are appended to the URL as query parameters. Here are |
|
|
|
|
some examples:: |
|
|
|
|
|
|
|
|
|
>>> from flask import Flask, url_for |
|
|
|
|
>>> app = Flask(__name__) |
|
|
|
|
>>> @app.route('/') |
|
|
|
|
... def index(): pass |
|
|
|
|
... |
|
|
|
|
>>> @app.route('/login') |
|
|
|
|
... def login(): pass |
|
|
|
|
... |
|
|
|
|
>>> @app.route('/user/<username>') |
|
|
|
|
... def profile(username): pass |
|
|
|
|
... |
|
|
|
|
>>> with app.test_request_context(): |
|
|
|
|
... print(url_for('index')) |
|
|
|
|
... print(url_for('login')) |
|
|
|
|
... print(url_for('login', next='/')) |
|
|
|
|
... print(url_for('profile', username='John Doe')) |
|
|
|
|
... |
|
|
|
|
/ |
|
|
|
|
/login |
|
|
|
|
/login?next=/ |
|
|
|
|
/user/John%20Doe |
|
|
|
|
|
|
|
|
|
(This also uses the :meth:`~flask.Flask.test_request_context` method, explained |
|
|
|
|
below. It tells Flask to behave as though it is handling a request, even |
|
|
|
|
though we are interacting with it through a Python shell. Have a look at the |
|
|
|
|
explanation below. :ref:`context-locals`). |
|
|
|
|
To build a URL to a specific function, use the :func:`~flask.url_for` function. |
|
|
|
|
It accepts the name of the function as its first argument and any number of |
|
|
|
|
keyword arguments, each corresponding to a variable part of the URL rule. |
|
|
|
|
Unknown variable parts are appended to the URL as query parameters. |
|
|
|
|
|
|
|
|
|
Why would you want to build URLs using the URL reversing function |
|
|
|
|
:func:`~flask.url_for` instead of hard-coding them into your templates? |
|
|
|
|
There are three good reasons for this: |
|
|
|
|
|
|
|
|
|
1. Reversing is often more descriptive than hard-coding the URLs. More |
|
|
|
|
importantly, it allows you to change URLs in one go, without having to |
|
|
|
|
remember to change URLs all over the place. |
|
|
|
|
2. URL building will handle escaping of special characters and Unicode |
|
|
|
|
data transparently for you, so you don't have to deal with them. |
|
|
|
|
3. If your application is placed outside the URL root - say, in |
|
|
|
|
``/myapplication`` instead of ``/`` - :func:`~flask.url_for` will handle |
|
|
|
|
that properly for you. |
|
|
|
|
1. Reversing is often more descriptive than hard-coding the URLs. |
|
|
|
|
2. You can change your URLs in one go instead of needing to remember to |
|
|
|
|
manually change hard-coded URLs. |
|
|
|
|
3. URL building handles escaping of special characters and Unicode data |
|
|
|
|
transparently. |
|
|
|
|
4. If your application is placed outside the URL root, for example, in |
|
|
|
|
``/myapplication`` instead of ``/``, :func:`~flask.url_for` properly |
|
|
|
|
handles that for you. |
|
|
|
|
|
|
|
|
|
For example, here we use the :meth:`~flask.Flask.test_request_context` method |
|
|
|
|
to try out :func:`~flask.url_for`. :meth:`~flask.Flask.test_request_context` |
|
|
|
|
tells Flask to behave as though it's handling a request even while we use a |
|
|
|
|
Python shell. See :ref:`context-locals`. :: |
|
|
|
|
|
|
|
|
|
from flask import Flask, url_for |
|
|
|
|
|
|
|
|
|
app = Flask(__name__) |
|
|
|
|
|
|
|
|
|
@app.route('/') |
|
|
|
|
def index(): |
|
|
|
|
return 'index' |
|
|
|
|
|
|
|
|
|
@app.route('/login') |
|
|
|
|
def login(): |
|
|
|
|
return 'login' |
|
|
|
|
|
|
|
|
|
@app.route('/user/<username>') |
|
|
|
|
def profile(username): |
|
|
|
|
return '{}'s profile'.format(username) |
|
|
|
|
|
|
|
|
|
with app.test_request_context(): |
|
|
|
|
print(url_for('index')) |
|
|
|
|
print(url_for('login')) |
|
|
|
|
print(url_for('login', next='/')) |
|
|
|
|
print(url_for('profile', username='John Doe')) |
|
|
|
|
|
|
|
|
|
/ |
|
|
|
|
/login |
|
|
|
|
/login?next=/ |
|
|
|
|
/user/John%20Doe |
|
|
|
|
|
|
|
|
|
HTTP Methods |
|
|
|
|
```````````` |
|
|
|
|
|
|
|
|
|
HTTP (the protocol web applications are speaking) knows different methods for |
|
|
|
|
accessing URLs. By default, a route only answers to ``GET`` requests, but that |
|
|
|
|
can be changed by providing the ``methods`` argument to the |
|
|
|
|
:meth:`~flask.Flask.route` decorator. Here are some examples:: |
|
|
|
|
|
|
|
|
|
from flask import request |
|
|
|
|
Web applications use different HTTP methods when accessing URLs. You should |
|
|
|
|
familiarize yourself with the HTTP methods as you work with Flask. By default, |
|
|
|
|
a route only answers to ``GET`` requests. You can use the ``methods`` argument |
|
|
|
|
of the :meth:`~flask.Flask.route` decorator to handle different HTTP methods. |
|
|
|
|
:: |
|
|
|
|
|
|
|
|
|
@app.route('/login', methods=['GET', 'POST']) |
|
|
|
|
def login(): |
|
|
|
|
if request.method == 'POST': |
|
|
|
|
return do_the_login() |
|
|
|
|
do_the_login() |
|
|
|
|
else: |
|
|
|
|
return show_the_login_form() |
|
|
|
|
|
|
|
|
|
If ``GET`` is present, ``HEAD`` will be added automatically for you. You |
|
|
|
|
don't have to deal with that. It will also make sure that ``HEAD`` requests |
|
|
|
|
are handled as the `HTTP RFC`_ (the document describing the HTTP |
|
|
|
|
protocol) demands, so you can completely ignore that part of the HTTP |
|
|
|
|
specification. Likewise, as of Flask 0.6, ``OPTIONS`` is implemented for you |
|
|
|
|
automatically as well. |
|
|
|
|
|
|
|
|
|
You have no idea what an HTTP method is? Worry not, here is a quick |
|
|
|
|
introduction to HTTP methods and why they matter: |
|
|
|
|
|
|
|
|
|
The HTTP method (also often called "the verb") tells the server what the |
|
|
|
|
client wants to *do* with the requested page. The following methods are |
|
|
|
|
very common: |
|
|
|
|
|
|
|
|
|
``GET`` |
|
|
|
|
The browser tells the server to just *get* the information stored on |
|
|
|
|
that page and send it. This is probably the most common method. |
|
|
|
|
|
|
|
|
|
``HEAD`` |
|
|
|
|
The browser tells the server to get the information, but it is only |
|
|
|
|
interested in the *headers*, not the content of the page. An |
|
|
|
|
application is supposed to handle that as if a ``GET`` request was |
|
|
|
|
received but to not deliver the actual content. In Flask you don't |
|
|
|
|
have to deal with that at all, the underlying Werkzeug library handles |
|
|
|
|
that for you. |
|
|
|
|
|
|
|
|
|
``POST`` |
|
|
|
|
The browser tells the server that it wants to *post* some new |
|
|
|
|
information to that URL and that the server must ensure the data is |
|
|
|
|
stored and only stored once. This is how HTML forms usually |
|
|
|
|
transmit data to the server. |
|
|
|
|
|
|
|
|
|
``PUT`` |
|
|
|
|
Similar to ``POST`` but the server might trigger the store procedure |
|
|
|
|
multiple times by overwriting the old values more than once. Now you |
|
|
|
|
might be asking why this is useful, but there are some good reasons |
|
|
|
|
to do it this way. Consider that the connection is lost during |
|
|
|
|
transmission: in this situation a system between the browser and the |
|
|
|
|
server might receive the request safely a second time without breaking |
|
|
|
|
things. With ``POST`` that would not be possible because it must only |
|
|
|
|
be triggered once. |
|
|
|
|
|
|
|
|
|
``DELETE`` |
|
|
|
|
Remove the information at the given location. |
|
|
|
|
|
|
|
|
|
``OPTIONS`` |
|
|
|
|
Provides a quick way for a client to figure out which methods are |
|
|
|
|
supported by this URL. Starting with Flask 0.6, this is implemented |
|
|
|
|
for you automatically. |
|
|
|
|
|
|
|
|
|
Now the interesting part is that in HTML4 and XHTML1, the only methods a |
|
|
|
|
form can submit to the server are ``GET`` and ``POST``. But with JavaScript |
|
|
|
|
and future HTML standards you can use the other methods as well. Furthermore |
|
|
|
|
HTTP has become quite popular lately and browsers are no longer the only |
|
|
|
|
clients that are using HTTP. For instance, many revision control systems |
|
|
|
|
use it. |
|
|
|
|
show_the_login_form() |
|
|
|
|
|
|
|
|
|
If ``GET`` is present, Flask automatically adds support for the ``HEAD`` method |
|
|
|
|
and handles ``HEAD`` requests according to the the `HTTP RFC`_. Likewise, |
|
|
|
|
``OPTIONS`` is automatically implemented for you. |
|
|
|
|
|
|
|
|
|
.. _HTTP RFC: https://www.ietf.org/rfc/rfc2068.txt |
|
|
|
|
|
|
|
|
|