Templates

You’ve written the authentication views for your application, but ifyou’re running the server and try to go to any of the URLs, you’ll see aTemplateNotFound error. That’s because the views are callingrender_template(), but you haven’t written the templates yet.The template files will be stored in the templates directory insidethe flaskr package.

Templates are files that contain static data as well as placeholdersfor dynamic data. A template is rendered with specific data to produce afinal document. Flask uses the Jinja template library to rendertemplates.

In your application, you will use templates to render HTML whichwill display in the user’s browser. In Flask, Jinja is configured toautoescape any data that is rendered in HTML templates. This meansthat it’s safe to render user input; any characters they’ve entered thatcould mess with the HTML, such as < and > will be escaped withsafe values that look the same in the browser but don’t cause unwantedeffects.

Jinja looks and behaves mostly like Python. Special delimiters are usedto distinguish Jinja syntax from the static data in the template.Anything between {{ and }} is an expression that will be outputto the final document. {% and %} denotes a control flowstatement like if and for. Unlike Python, blocks are denotedby start and end tags rather than indentation since static text withina block could change indentation.

The Base Layout

Each page in the application will have the same basic layout around adifferent body. Instead of writing the entire HTML structure in eachtemplate, each template will extend a base template and overridespecific sections.

flaskr/templates/base.html

  1. <!doctype html>
  2. <title>{% block title %}{% endblock %} - Flaskr</title>
  3. <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
  4. <nav>
  5. <h1>Flaskr</h1>
  6. <ul>
  7. {% if g.user %}
  8. <li><span>{{ g.user['username'] }}</span>
  9. <li><a href="{{ url_for('auth.logout') }}">Log Out</a>
  10. {% else %}
  11. <li><a href="{{ url_for('auth.register') }}">Register</a>
  12. <li><a href="{{ url_for('auth.login') }}">Log In</a>
  13. {% endif %}
  14. </ul>
  15. </nav>
  16. <section class="content">
  17. <header>
  18. {% block header %}{% endblock %}
  19. </header>
  20. {% for message in get_flashed_messages() %}
  21. <div class="flash">{{ message }}</div>
  22. {% endfor %}
  23. {% block content %}{% endblock %}
  24. </section>

g is automatically available in templates. Based on ifg.user is set (from load_logged_in_user), either the usernameand a log out link are displayed, or links to register and log inare displayed. url_for() is also automatically available, and isused to generate URLs to views instead of writing them out manually.

After the page title, and before the content, the template loops overeach message returned by get_flashed_messages(). You usedflash() in the views to show error messages, and this is the codethat will display them.

There are three blocks defined here that will be overridden in the othertemplates:

  • {% block title %} will change the title displayed in thebrowser’s tab and window title.

  • {% block header %} is similar to title but will change thetitle displayed on the page.

  • {% block content %} is where the content of each page goes, suchas the login form or a blog post.

The base template is directly in the templates directory. To keepthe others organized, the templates for a blueprint will be placed in adirectory with the same name as the blueprint.

Register

flaskr/templates/auth/register.html

  1. {% extends 'base.html' %}
  2.  
  3. {% block header %}
  4. <h1>{% block title %}Register{% endblock %}</h1>
  5. {% endblock %}
  6.  
  7. {% block content %}
  8. <form method="post">
  9. <label for="username">Username</label>
  10. <input name="username" id="username" required>
  11. <label for="password">Password</label>
  12. <input type="password" name="password" id="password" required>
  13. <input type="submit" value="Register">
  14. </form>
  15. {% endblock %}

{% extends 'base.html' %} tells Jinja that this template shouldreplace the blocks from the base template. All the rendered content mustappear inside {% block %} tags that override blocks from the basetemplate.

A useful pattern used here is to place {% block title %} inside{% block header %}. This will set the title block and then outputthe value of it into the header block, so that both the window and pageshare the same title without writing it twice.

The input tags are using the required attribute here. This tellsthe browser not to submit the form until those fields are filled in. Ifthe user is using an older browser that doesn’t support that attribute,or if they are using something besides a browser to make requests, youstill want to validate the data in the Flask view. It’s important toalways fully validate the data on the server, even if the client doessome validation as well.

Log In

This is identical to the register template except for the title andsubmit button.

flaskr/templates/auth/login.html

  1. {% extends 'base.html' %}
  2.  
  3. {% block header %}
  4. <h1>{% block title %}Log In{% endblock %}</h1>
  5. {% endblock %}
  6.  
  7. {% block content %}
  8. <form method="post">
  9. <label for="username">Username</label>
  10. <input name="username" id="username" required>
  11. <label for="password">Password</label>
  12. <input type="password" name="password" id="password" required>
  13. <input type="submit" value="Log In">
  14. </form>
  15. {% endblock %}

Register A User

Now that the authentication templates are written, you can register auser. 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 seethat the browser shows an error message. Try removing the requiredattributes from the register.html template and click “Register”again. Instead of the browser showing an error, the page will reload andthe error from flash() in the view will be shown.

Fill out a username and password and you’ll be redirected to the loginpage. Try entering an incorrect username, or the correct username andincorrect password. If you log in you’ll get an error because there’sno index view to redirect to yet.

Continue to Static Files.