I. What is the Jinja2 Template Engine?¶
In web development, we often need to combine dynamic data (such as user information or article lists retrieved from a database) with static pages (HTML) to generate the final web page. A template engine is a tool designed to solve this problem—it allows embedding code logic directly within HTML to dynamically generate content.
Flask, a popular Python web framework, uses Jinja2 as its default template engine. Jinja2 is a powerful yet syntax-simple Python template engine that supports variables, conditional statements, loops, template inheritance, and more, enabling efficient creation of reusable and maintainable templates.
II. Basic Jinja2 Syntax¶
1. Variables and Expressions¶
The most fundamental operation in a template is displaying variables. Variables are embedded using the syntax {{ variable_name }} and are passed to the template from view functions (Python code).
Example:
If a variable username = "小明" is defined in a view function, the template would use:
<p>Welcome, {{ username }}!</p>
Rendering this would output: Welcome, 小明!
Variables can be of types like strings, numbers, lists, or dictionaries, and you can access their attributes or indices:
<!-- For a dictionary -->
<p>{{ user.age }}</p> <!-- Outputs the "age" value of the "user" dictionary -->
<!-- For a list -->
<p>{{ users[0] }}</p> <!-- Outputs the first element of the "users" list -->
2. Control Structures: Conditionals and Loops¶
Jinja2 supports conditional checks and loops to dynamically render content based on different scenarios.
Conditional Checks (if-else):
{% if is_login %}
<p>Welcome back!</p>
{% else %}
<p>Please log in first</p>
{% endif %}
Loops (for):
Use {% for %} to iterate over lists or dictionaries. The loop variable provides loop state information (e.g., index, total length, or whether it’s the last element):
<ul>
{% for item in todo_list %}
<li>
{{ loop.index }}. {{ item }}
{% if loop.last %} <!-- Check if it's the last element -->
<small>(This is the last item)</small>
{% endif %}
</li>
{% endfor %}
</ul>
If the loop’s list is empty, use {% else %} to display default content:
{% for item in todo_list %}
<li>{{ item }}</li>
{% else %}
<p>The list is empty</p>
{% endfor %}
3. Template Inheritance and Inclusion¶
To avoid code duplication, Jinja2 offers template inheritance and template inclusion.
Template Inheritance (Extend):
- Define a parent template (e.g., base.html) containing common structures (header, footer, navigation).
- Child templates inherit from the parent using {% extends "base.html" %} and override specific sections.
Parent Template (base.html):
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}Default Title{% endblock %}</title>
</head>
<body>
<header>
{% block header %}<h1>Website Header</h1>{% endblock %}
</header>
<main>
{% block content %}{% endblock %}
</main>
<footer>
{% block footer %}<p>Website Footer</p>{% endblock %}
</footer>
</body>
</html>
Child Template (index.html):
{% extends "base.html" %} <!-- Inherit from the parent template -->
{% block title %}Home Page{% endblock %} <!-- Override the "title" block -->
{% block content %} <!-- Override the "content" block -->
<p>This is the home page content.</p>
<ul>
<li>Item 1</li>
<li>Item 2</li>
</ul>
{% endblock %}
Template Inclusion (Include):
Reuse small template fragments (e.g., headers or footers) by inserting them directly into the current template:
{% include "header.html" %} <!-- Inserts the content of header.html -->
4. Filters: Processing Variables¶
Filters modify variables using the | operator. Common filters include:
upper/lower: Convert to uppercase/lowercase
{{ name|upper }}→ OutputsNAMEcapitalize: Capitalize the first letter
{{ name|capitalize }}→ OutputsNametruncate(n): Truncate text to the firstncharacters
{{ long_text|truncate(20) }}→ Truncates to the first 20 characterssafe: Disable HTML escaping (use cautiously to prevent XSS attacks)
{{ raw_html|safe }}→ Renders raw HTML directly
Example:
<p>{{ "hello"|upper }}</p> <!-- Outputs HELLO -->
<p>{{ "123"|int + 456 }}</p> <!-- Converts to integer and adds 456 -->
<p>{{ "Flask is great!"|truncate(10) }}</p> <!-- Truncates to "Flask is gr" -->
III. Combining Flask with Jinja2¶
1. Template File Structure¶
Flask by default loads templates from a templates folder in the project root. A typical project structure might look like:
myapp/
├── app.py
└── templates/
├── base.html
├── index.html
└── user.html
2. Core Function for Rendering Templates¶
View functions use render_template to render templates and pass variables:
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def index():
# Prepare data
users = [
{"name": "Alice", "age": 25},
{"name": "Bob", "age": 30}
]
return render_template('index.html', users=users) # Pass "users" to the template
if __name__ == '__main__':
app.run(debug=True)
3. Complete Example: User List Page¶
Template File (templates/user_list.html):
{% extends "base.html" %} <!-- Inherit from the parent template -->
{% block content %}
<h1>User List</h1>
<ul>
{% for user in users %} <!-- Iterate over the "users" list -->
<li>
{{ loop.index }}. {{ user.name }} ({{ user.age }} years old)
{% if user.age > 28 %}
<span style="color:red;">(Adult)</span>
{% endif %}
</li>
{% else %}
<p>No users found</p>
{% endfor %}
</ul>
{% endblock %}
View Function (app.py):
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/users')
def user_list():
# Simulate database query results
user_data = [
{"name": "Alice", "age": 25},
{"name": "Bob", "age": 30},
{"name": "Charlie", "age": 22}
]
return render_template('user_list.html', users=user_data) # Pass data to the template
if __name__ == '__main__':
app.run(debug=True)
IV. Summary and Learning Recommendations¶
Jinja2 is a core component of Flask, and mastering its syntax significantly improves web development efficiency. Key concepts to focus on:
1. Variables and Expressions: {{ variable }}
2. Control Structures: if-else, for loops
3. Template Reusability: Inheritance (extends) and inclusion (include)
4. Filters: | for variable processing
Practice Suggestions:
- Build a simple personal blog using template inheritance for navigation bar reuse
- Practice rendering article lists with loops and use filters to truncate long text
- Experiment with the safe filter to render rich text content
By practicing regularly, you’ll become proficient with Jinja2’s flexible syntax, creating more elegant and efficient Flask applications!