6.4. Templating#
As we’ve seen in previous examples, it’s possible to return HTML code directly from a route function, but this approach quickly becomes difficult to manage. Imagine writing the same HTML structure repeatedly, or trying to change the layout of multiple pages - it can become a real headache! Instead of writing HTML inside our Python code, Flask allows us to use templates.
Templates make it possible to separate the HTML structure from the logic in our Python code. Flask uses the Jinja2 templating engine, which allows us to create dynamic HTML pages by inserting Python-like logic (loops, variables, etc.) into the HTML.
6.4.1. Jinja#
Jinja is a powerful templating language for Python. It allows you to embed variables, use control structures like loops, and create reusable layouts. Here’s an example of how Jinja works:
1from jinja2 import Template
2
3# Create a Jinja2 template
4template = Template('Hello, {{ name }}!')
5
6# Render the template with a value for "name"
7rendered = template.render(name='John')
8print(rendered)
Explanation:
Line 4: A template is created with a placeholder for the
name
variable.Line 7: The template is rendered with the value
"John"
passed toname
, and it outputs:"Hello, John!"
.
6.4.2. Jinja Syntax#
The Template Designer Documentation provided by Jinja outlines the syntax available inside Jinja templates including:
variables
filters
loops
6.4.3. Templates in Flask#
Flask looks for template files inside a folder called templates in your project.
Instead of returning HTML directly, you can load and render templates using the
render_template()
function.
Complete Example
Let’s see how we can use templates in the movie reviews website to display the list of movies.
Project structure:
├── app.py
├── movies.db
└── templates
└── index.html
1from flask import Flask, render_template
2from sqlalchemy import create_engine, text
3
4app = Flask(__name__)
5
6# Connect to the database
7engine = create_engine('sqlite:///movies.db')
8
9@app.route('/')
10def home():
11 # SQL query to select all movies
12 query = text("SELECT * FROM reviews")
13 result = engine.execute(query).fetchall()
14
15 # Render the template and pass the result
16 return render_template('index.html', movies=result)
17
18app.run(debug=True)
Explanation:
render_template()
is used to:load the
index.html
file from thetemplates`
folder,pass the query
result
to the template engine, namedmovies
inside the template context.
This is the index.html
template file inside the templates
folder:
1<!DOCTYPE html>
2<html lang="en">
3 <head>
4 <title>Movie Reviews</title>
5 </head>
6 <body>
7 <h1>Movie Reviews</h1>
8 <ul>
9 {% for movie in movies %}
10 <li>{{ movie[1] }} ({{ movie[2] }}) - Score: {{ movie[5] }}</li>
11 {% endfor %}
12 </ul>
13 </body>
14</html>
Explanation:
Lines 9-11: The
for
loop iterates over each movie and displays its title, year, and score using Jinja2 syntax.
6.4.4. Extending Templates#
Flask templates can be extended to create a base layout that other pages can inherit. This is useful when you have common elements like headers or footers across multiple pages.
1{% extends 'base.html' %}
2
3{% block title %}Home - Movie Reviews{% endblock %}
4
5{% block content %}
6 <ul>
7 {% for movie in movies %}
8 <li>{{ movie[1] }} ({{ movie[2] }}) - Score: {{ movie[5] }}</li>
9 {% endfor %}
10 </ul>
11{% endblock %}
Explanation:
{% extends 'base.html' %}
makesindex.html
inherit the layout frombase.html
.{% block title %}
overrides the title from the base template.{% block content %}
is overridden to display the list of movies.
1<!DOCTYPE html>
2<html lang="en">
3 <head>
4 <title>{% block title %}Movie Reviews{% endblock %}</title>
5 </head>
6 <body>
7 <header>
8 <h1>Welcome to the Movie Reviews Website</h1>
9 </header>
10
11 <div class="content">
12 {% block content %}{% endblock %}
13 </div>
14 </body>
15</html>
Explanation:
{% block title %}
and{% block content %}
are placeholders that child templates can override.
6.4.5. Static Files in Templates#
As we saw previously in Serving Static Files, Flask serves static files like CSS, JavaScript, or images
from a folder called static
.
We manually specified the path to a stylesheet. For example:
<link rel="stylesheet" type="text/css" href="/static/css/styles.css">
However this path will change if we change static_url_path
when we create the
Flask
object. To make sure that we correctly reference the path to static files
we can use the url_for
template function.
Here’s a simple example:
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
Complete Example
Project structure:
├── app.py
├── movies.db
├── static
│ └── style.css
└── templates
├── base.html
└── index.html
1<!DOCTYPE html>
2<html lang="en">
3 <head>
4 <title>{% block title %}Movie Reviews{% endblock %}</title>
5 <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
6 </head>
7 <body>
8 <header>
9 <h1>Welcome to the Movie Reviews Website</h1>
10 </header>
11
12 <div class="content">
13 {% block content %}{% endblock %}
14 </div>
15 </body>
16</html>
Explanation:
Line 5:
{{ url_for('static', filename='style.css') }}
generates the correct URL to thestyle.css
file.Now, the custom styles from
style.css
will be applied to all pages that use thebase.html
layout.
1 body {
2 font-family: Arial, sans-serif;
3 background-color: #f0f0f0;
4 }
5
6 h1 {
7 color: #333;
8 }
9
10 ul {
11 list-style-type: none;
12 }
13
14 li {
15 margin-bottom: 10px;
16 }
6.4.6. Glossary#
- Render#
Rendering templates is the process of combining a predefined HTML template with dynamic data on the server to generate a complete web page that is then sent to the user’s browser. This allows for content to change while maintaining the same layout and structure.