Jinja2 Templates — Rendering HTML Pages
In this chapter, you will learn to use the Jinja2 template engine to render complete HTML pages and extract common layouts.
From strings to templates
In the previous chapter, view functions directly returned strings with HTML tags embedded in the lines, which could not be reused and were difficult to maintain.
render_template()It is the entry point for Flask's template rendering: it loads HTML files, injects variables, and returns a complete HTML response.
Example
from flask import Flask, render_template
app = Flask(__name__)
@app.route("/")
def index():
# render_template('template file name', variable name=value, ...)
return render_template('index.html', title='EXAMPLE Blog')
Flask by default, in the project root directory'stemplates/Find templates in the folder.
Create template files
Create in the project root directorytemplates/folder, then createindex.html。
Example
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>{{ title }}</title>
</head>
<body>
<h1>{{ title }}</h1>
<p>Welcome, this is a page rendered with the Jinja2 template engine.</p>
</body>
</html>
Jinja2 template syntax overview
Jinja2 syntax is almost exactly the same as Django template syntax, and is also similar to Vue3's interpolation syntax.
| Purpose | Jinja2 / Django | Description |
|---|---|---|
| Output variables | {{ variable }} | Supports attribute access: {{ user.name }} |
| Loops | {% for item in list %}...{% endfor %} | Supports loop.index |
| Conditions | {% if cond %}...{% endif %} | Chainable: {% elif %} |
| Inheritance | {% extends 'base.html' %} | Must be on the first line |
| Block definitions | {% block name %}...{% endblock %} | Child templates fill in the gaps of the parent template |
Jinja2 and Django template syntax are almost identical, but Jinja2 is more flexible: you can write more complex Python expressions in templates, whereas Django templates deliberately restrict some capabilities to avoid business logic leaking into templates.
Template inheritance: base.html
Multiple pages share the navigation bar and footer, useTemplate inheritanceAvoid duplicate HTML.
Creating a base.html parent template
Example
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- block title: child template can override the page title -->
<title>{% block title %}EXAMPLE Blog{% endblock %}</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: #f5f5f5;
color: #333;
}
.navbar {
display: flex; justify-content: space-between; align-items: center;
padding: 16px 40px; background: #fff;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.navbar .logo { font-size: 22px; font-weight: bold; color: #e74c3c; text-decoration: none; }
.navbar a { margin-left: 20px; text-decoration: none; color: #333; }
.container { max-width: 960px; margin: 40px auto; padding: 0 20px; }
.footer { text-align: center; padding: 20px; color: #999; border-top: 1px solid #eee; }
</style>
{% block extra_head %}{% endblock %}
</head>
<body>
<header class="navbar">
<a href="/" class="logo">EXAMPLE Blog (Flask)</a>
<nav>
<a href="/">Home</a>
<a href="/about">About</a>
</nav>
</header>
<main class="container">
<!-- block content: child template fills in the page main content here -->
{% block content %}
{% endblock %}
</main>
<footer class="footer">
<p>© 2024 EXAMPLE Blog. Powered by Flask.</p>
</footer>
</body>
</html>
Child templates inherit the parent template
Example
{% extends 'base.html' %}
{% block title %}EXAMPLE Blog - Home{% endblock %}
{% block content %}
<h2>Latest Articles</h2>
<p>The article list will be displayed in later chapters.</p>
{% endblock %}
{% extends 'base.html' %}It must be written on the first line of the child template (except for comments). This is a hard requirement of Jinja2—the template engine needs to determine the inheritance relationship first.
url_for() generates links
Don't hardcode URLs, useurl_for()Look up the address by function name.
Example
@app.route("/")
def index(): ...
@app.route("/post/<int:post_id>")
def post_detail(post_id): ...
Example
The route changed (e.g.,/post/Change to/article/), in the templateurl_for()Automatically generate new addresses.
Static file configuration
Flask by default willstatic/directory as the static file root directory.
blog_project/ ├── static/ │ ├── css/ │ │ └── style.css │ ├── js/ │ │ └── main.js │ └── images/ │ └── logo.png ├── templates/ └── app.py
In templates, viaurl_for('static', filename='css/style.css')reference.
Chapter summary
In this chapter, you mastered the core of Jinja2 templates: render_template() to render templates, {{ }} to output variables, {% for/if %} control flow, base.html + block + extends template inheritance, and url_for() to generate links.
Now the blog page has become well-structured HTML, and the common parts have been extracted into base.html.
other extensions