mirror of https://github.com/mitsuhiko/flask.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
187 lines
6.8 KiB
187 lines
6.8 KiB
.. currentmodule:: flask |
|
|
|
Templates |
|
========= |
|
|
|
You've written the authentication views for your application, but if |
|
you're running the server and try to go to any of the URLs, you'll see a |
|
``TemplateNotFound`` error. That's because the views are calling |
|
:func:`render_template`, but you haven't written the templates yet. |
|
The template files will be stored in the ``templates`` directory inside |
|
the ``flaskr`` package. |
|
|
|
Templates are files that contain static data as well as placeholders |
|
for dynamic data. A template is rendered with specific data to produce a |
|
final document. Flask uses the `Jinja`_ template library to render |
|
templates. |
|
|
|
In your application, you will use templates to render `HTML`_ which |
|
will display in the user's browser. In Flask, Jinja is configured to |
|
*autoescape* any data that is rendered in HTML templates. This means |
|
that it's safe to render user input; any characters they've entered that |
|
could mess with the HTML, such as ``<`` and ``>`` will be *escaped* with |
|
*safe* values that look the same in the browser but don't cause unwanted |
|
effects. |
|
|
|
Jinja looks and behaves mostly like Python. Special delimiters are used |
|
to distinguish Jinja syntax from the static data in the template. |
|
Anything between ``{{`` and ``}}`` is an expression that will be output |
|
to the final document. ``{%`` and ``%}`` denotes a control flow |
|
statement like ``if`` and ``for``. Unlike Python, blocks are denoted |
|
by start and end tags rather than indentation since static text within |
|
a block could change indentation. |
|
|
|
.. _Jinja: http://jinja.pocoo.org/docs/templates/ |
|
.. _HTML: https://developer.mozilla.org/docs/Web/HTML |
|
|
|
|
|
The Base Layout |
|
--------------- |
|
|
|
Each page in the application will have the same basic layout around a |
|
different body. Instead of writing the entire HTML structure in each |
|
template, each template will *extend* a base template and override |
|
specific sections. |
|
|
|
.. code-block:: html+jinja |
|
:caption: ``flaskr/templates/base.html`` |
|
|
|
<!doctype html> |
|
<title>{% block title %}{% endblock %} - Flaskr</title> |
|
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}"> |
|
<nav> |
|
<h1>Flaskr</h1> |
|
<ul> |
|
{% if g.user %} |
|
<li><span>{{ g.user['username'] }}</span> |
|
<li><a href="{{ url_for('auth.logout') }}">Log Out</a> |
|
{% else %} |
|
<li><a href="{{ url_for('auth.register') }}">Register</a> |
|
<li><a href="{{ url_for('auth.login') }}">Log In</a> |
|
{% endif %} |
|
</ul> |
|
</nav> |
|
<section class="content"> |
|
<header> |
|
{% block header %}{% endblock %} |
|
</header> |
|
{% for message in get_flashed_messages() %} |
|
<div class="flash">{{ message }}</div> |
|
{% endfor %} |
|
{% block content %}{% endblock %} |
|
</section> |
|
|
|
:data:`g` is automatically available in templates. Based on if |
|
``g.user`` is set (from ``load_logged_in_user``), either the username |
|
and a log out link are displayed, otherwise links to register and log in |
|
are displayed. :func:`url_for` is also automatically available, and is |
|
used to generate URLs to views instead of writing them out manually. |
|
|
|
After the page title, and before the content, the template loops over |
|
each message returned by :func:`get_flashed_messages`. You used |
|
:func:`flash` in the views to show error messages, and this is the code |
|
that will display them. |
|
|
|
There are three blocks defined here that will be overridden in the other |
|
templates: |
|
|
|
#. ``{% block title %}`` will change the title displayed in the |
|
browser's tab and window title. |
|
|
|
#. ``{% block header %}`` is similar to ``title`` but will change the |
|
title displayed on the page. |
|
|
|
#. ``{% block content %}`` is where the content of each page goes, such |
|
as the login form or a blog post. |
|
|
|
The base template is directly in the ``templates`` directory. To keep |
|
the others organized, the templates for a blueprint will be placed in a |
|
directory with the same name as the blueprint. |
|
|
|
|
|
Register |
|
-------- |
|
|
|
.. code-block:: html+jinja |
|
:caption: ``flaskr/templates/auth/register.html`` |
|
|
|
{% extends 'base.html' %} |
|
|
|
{% block header %} |
|
<h1>{% block title %}Register{% endblock %}</h1> |
|
{% endblock %} |
|
|
|
{% block content %} |
|
<form method="post"> |
|
<label for="username">Username</label> |
|
<input name="username" id="username" required> |
|
<label for="password">Password</label> |
|
<input type="password" name="password" id="password" required> |
|
<input type="submit" value="Register"> |
|
</form> |
|
{% endblock %} |
|
|
|
``{% extends 'base.html' %}`` tells Jinja that this template should |
|
replace the blocks from the base template. All the rendered content must |
|
appear inside ``{% block %}`` tags that override blocks from the base |
|
template. |
|
|
|
A useful pattern used here is to place ``{% block title %}`` inside |
|
``{% block header %}``. This will set the title block and then output |
|
the value of it into the header block, so that both the window and page |
|
share the same title without writing it twice. |
|
|
|
The ``input`` tags are using the ``required`` attribute here. This tells |
|
the browser not to submit the form until those fields are filled in. If |
|
the user is using an older browser that doesn't support that attribute, |
|
or if they are using something besides a browser to make requests, you |
|
still want to validate the data in the Flask view. It's important to |
|
always fully validate the data on the server, even if the client does |
|
some validation as well. |
|
|
|
|
|
Log In |
|
------ |
|
|
|
This is identical to the register template except for the title and |
|
submit button. |
|
|
|
.. code-block:: html+jinja |
|
:caption: ``flaskr/templates/auth/login.html`` |
|
|
|
{% extends 'base.html' %} |
|
|
|
{% block header %} |
|
<h1>{% block title %}Log In{% endblock %}</h1> |
|
{% endblock %} |
|
|
|
{% block content %} |
|
<form method="post"> |
|
<label for="username">Username</label> |
|
<input name="username" id="username" required> |
|
<label for="password">Password</label> |
|
<input type="password" name="password" id="password" required> |
|
<input type="submit" value="Log In"> |
|
</form> |
|
{% endblock %} |
|
|
|
|
|
Register A User |
|
--------------- |
|
|
|
Now that the authentication templates are written, you can register a |
|
user. Make sure the server is still running (``flask run`` if it's not), |
|
then go to http://127.0.0.1:5000/auth/register. |
|
|
|
Try clicking the "Register" button without filling out the form and see |
|
that the browser shows an error message. Try removing the ``required`` |
|
attributes from the ``register.html`` template and click "Register" |
|
again. Instead of the browser showing an error, the page will reload and |
|
the error from :func:`flash` in the view will be shown. |
|
|
|
Fill out a username and password and you'll be redirected to the login |
|
page. Try entering an incorrect username, or the correct username and |
|
incorrect password. If you log in you'll get an error because there's |
|
no ``index`` view to redirect to yet. |
|
|
|
Continue to :doc:`static`.
|
|
|