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
|
||||
-------
|
||||
|
||||
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,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
|
||||
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::
|
||||
Take these two rules::
|
||||
|
||||
@app.route('/projects/')
|
||||
def projects():
|
||||
return 'The project page'
|
||||
@app.route('/projects/')
|
||||
def projects():
|
||||
return 'The project page'
|
||||
|
||||
@app.route('/about')
|
||||
def about():
|
||||
return 'The about page'
|
||||
@app.route('/about')
|
||||
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.
|
||||
|
||||
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.
|
||||
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::
|
||||
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?
|
||||
|
||||
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?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`).
|
||||
|
||||
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 (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()
|
||||
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.
|
||||
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
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue