forked from orbit-oss/flask
Merge pull request #2277 from jlara310/master
Improve quickstart's Routing section
This commit is contained in:
commit
c01ddc59b7
1 changed files with 96 additions and 152 deletions
|
|
@ -159,14 +159,11 @@ Have another debugger in mind? See :ref:`working-with-debuggers`.
|
||||||
Routing
|
Routing
|
||||||
-------
|
-------
|
||||||
|
|
||||||
Modern web applications have beautiful URLs. This helps people remember
|
Modern web applications use meaningful URLs to help users. Users are more
|
||||||
the URLs, which is especially handy for applications that are used from
|
likely to like a page and come back if the page uses a meaningful URL they can
|
||||||
mobile devices with slower network connections. If the user can directly
|
remember and use to directly visit a page.
|
||||||
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.
|
|
||||||
|
|
||||||
As you have seen above, the :meth:`~flask.Flask.route` decorator is used to
|
Use the :meth:`~flask.Flask.route` decorator to bind a function to a URL. ::
|
||||||
bind a function to a URL. Here are some basic examples::
|
|
||||||
|
|
||||||
@app.route('/')
|
@app.route('/')
|
||||||
def index():
|
def index():
|
||||||
|
|
@ -176,16 +173,16 @@ bind a function to a URL. Here are some basic examples::
|
||||||
def hello():
|
def hello():
|
||||||
return 'Hello, World'
|
return 'Hello, World'
|
||||||
|
|
||||||
But there is more to it! You can make certain parts of the URL dynamic and
|
You can do more! You can make parts of the URL dynamic and attach multiple
|
||||||
attach multiple rules to a function.
|
rules to a function.
|
||||||
|
|
||||||
Variable Rules
|
Variable Rules
|
||||||
``````````````
|
``````````````
|
||||||
|
|
||||||
To add variable parts to a URL you can mark these special sections as
|
You can add variable sections to a URL by marking sections with
|
||||||
``<variable_name>``. Such a part is then passed as a keyword argument to your
|
``<variable_name>``. Your function then receives the ``<variable_name>``
|
||||||
function. Optionally a converter can be used by specifying a rule with
|
as a keyword argument. Optionally, you can use a converter to specify the type
|
||||||
``<converter:variable_name>``. Here are some nice examples::
|
of the argument like ``<converter:variable_name>``. ::
|
||||||
|
|
||||||
@app.route('/user/<username>')
|
@app.route('/user/<username>')
|
||||||
def show_user_profile(username):
|
def show_user_profile(username):
|
||||||
|
|
@ -197,175 +194,122 @@ function. Optionally a converter can be used by specifying a rule with
|
||||||
# show the post with the given id, the id is an integer
|
# show the post with the given id, the id is an integer
|
||||||
return 'Post %d' % post_id
|
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
|
||||||
|
|
||||||
=========== ===============================================
|
Converter types:
|
||||||
`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
|
|
||||||
=========== ===============================================
|
|
||||||
|
|
||||||
.. 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
|
Unique URLs / Redirection Behavior
|
||||||
behind that module is to ensure beautiful and unique URLs based on
|
``````````````````````````````````
|
||||||
precedents laid down by Apache and earlier HTTP servers.
|
|
||||||
|
|
||||||
Take these two rules::
|
Take these two rules::
|
||||||
|
|
||||||
@app.route('/projects/')
|
@app.route('/projects/')
|
||||||
def projects():
|
def projects():
|
||||||
return 'The project page'
|
return 'The project page'
|
||||||
|
|
||||||
@app.route('/about')
|
@app.route('/about')
|
||||||
def about():
|
def about():
|
||||||
return 'The about page'
|
return 'The about page'
|
||||||
|
|
||||||
Though they look rather similar, they differ in their use of the trailing
|
Though they look similar, they differ in their use of the trailing slash in
|
||||||
slash in the URL *definition*. In the first case, the canonical URL for the
|
the URL. In the first case, the canonical URL for the ``projects`` endpoint
|
||||||
``projects`` endpoint has a trailing slash. In that sense, it is similar to
|
uses a trailing slash. It's similar to a folder in a file system; if you
|
||||||
a folder on a filesystem. Accessing it without a trailing slash will cause
|
access the URL without a trailing slash, Flask redirects you to the
|
||||||
Flask to redirect to the canonical URL with the trailing slash.
|
canonical URL with the trailing slash.
|
||||||
|
|
||||||
In the second case, however, the URL is defined without a trailing slash,
|
In the second case, however, the URL definition lacks a trailing slash,
|
||||||
rather like the pathname of a file on UNIX-like systems. Accessing the URL
|
like the pathname of a file on UNIX-like systems. Accessing the URL with a
|
||||||
with a trailing slash will produce a 404 "Not Found" error.
|
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.
|
|
||||||
|
|
||||||
|
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:
|
||||||
|
|
||||||
URL Building
|
URL Building
|
||||||
````````````
|
````````````
|
||||||
|
|
||||||
If it can match URLs, can Flask also generate them? Of course it can. To
|
To build a URL to a specific function, use the :func:`~flask.url_for` function.
|
||||||
build a URL to a specific function you can use the :func:`~flask.url_for`
|
It accepts the name of the function as its first argument and any number of
|
||||||
function. It accepts the name of the function as first argument and a number
|
keyword arguments, each corresponding to a variable part of the URL rule.
|
||||||
of keyword arguments, each corresponding to the variable part of the URL rule.
|
Unknown variable parts are appended to the URL as query parameters.
|
||||||
Unknown variable parts are appended to the URL as query parameters. Here are
|
|
||||||
some examples::
|
Why would you want to build URLs using the URL reversing function
|
||||||
|
:func:`~flask.url_for` instead of hard-coding them into your templates?
|
||||||
|
|
||||||
|
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'))
|
||||||
|
|
||||||
>>> 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
|
||||||
/login?next=/
|
/login?next=/
|
||||||
/user/John%20Doe
|
/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`).
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
|
|
||||||
HTTP Methods
|
HTTP Methods
|
||||||
````````````
|
````````````
|
||||||
|
|
||||||
HTTP (the protocol web applications are speaking) knows different methods for
|
Web applications use different HTTP methods when accessing URLs. You should
|
||||||
accessing URLs. By default, a route only answers to ``GET`` requests, but that
|
familiarize yourself with the HTTP methods as you work with Flask. By default,
|
||||||
can be changed by providing the ``methods`` argument to the
|
a route only answers to ``GET`` requests. You can use the ``methods`` argument
|
||||||
:meth:`~flask.Flask.route` decorator. Here are some examples::
|
of the :meth:`~flask.Flask.route` decorator to handle different HTTP methods.
|
||||||
|
::
|
||||||
from flask import request
|
|
||||||
|
|
||||||
@app.route('/login', methods=['GET', 'POST'])
|
@app.route('/login', methods=['GET', 'POST'])
|
||||||
def login():
|
def login():
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
return do_the_login()
|
do_the_login()
|
||||||
else:
|
else:
|
||||||
return show_the_login_form()
|
show_the_login_form()
|
||||||
|
|
||||||
If ``GET`` is present, ``HEAD`` will be added automatically for you. You
|
If ``GET`` is present, Flask automatically adds support for the ``HEAD`` method
|
||||||
don't have to deal with that. It will also make sure that ``HEAD`` requests
|
and handles ``HEAD`` requests according to the the `HTTP RFC`_. Likewise,
|
||||||
are handled as the `HTTP RFC`_ (the document describing the HTTP
|
``OPTIONS`` is automatically implemented for you.
|
||||||
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.
|
|
||||||
|
|
||||||
.. _HTTP RFC: https://www.ietf.org/rfc/rfc2068.txt
|
.. _HTTP RFC: https://www.ietf.org/rfc/rfc2068.txt
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue