In web development, we often need to display backend data (such as user information, product lists, article content, etc.) on the frontend page. Manually splicing HTML and data becomes extremely cumbersome and error-prone. A template engine is exactly the tool to solve this problem—it allows embedding dynamic content in HTML, enabling backend data to be “injected” into the page to generate the final web page.

I. What is Jinja2 and a Template Engine?

A template engine essentially combines backend data with HTML templates to generate web pages that can be directly displayed to users. It acts as a “template tool,” allowing developers to focus on separating data logic and page structure instead of repeatedly writing static HTML and dynamic data splicing code.

Jinja2 is the default template engine for the Flask framework, implemented in Python with a concise and powerful syntax. It supports variable substitution, conditional judgment, loops, filters, and other features, efficiently handling dynamic data rendering.

II. Basic Process of Using Jinja2 in Flask

To use Jinja2 in Flask, follow these steps:

1. Prepare the Environment: Install Flask

Ensure Flask is installed. If not, install it via pip:

pip install flask

2. Create a Flask Application and Route

Create app.py in the project root directory and define a simple Flask application and route to provide data and render templates:

from flask import Flask, render_template  # Import Flask and template rendering tool

app = Flask(__name__)  # Create Flask application instance

# Define route: execute index function when accessing the homepage
@app.route('/')
def index():
    # Prepare backend data (can be a dictionary, list, object, etc.)
    user_info = {
        'name': '小明',
        'age': 20,
        'hobbies': ['篮球', '编程', '阅读'],  # Hobby list
        'is_student': True,  # Whether a student
        'posts': [  # Article list
            {'title': 'Python入门教程', 'author': '小明', 'date': '2023-01-15'},
            {'title': 'Flask实战', 'author': '小明', 'date': '2023-02-20'}
        ]
    }
    # Render template and pass data
    return render_template('index.html', **user_info)  # **user_info unpacks the dictionary into parameters

if __name__ == '__main__':
    app.run(debug=True)  # Run in debug mode

3. Create a Template File

Flask by default looks for template files in the templates folder (create it manually if it doesn’t exist). Create the templates folder in the project root and add index.html as the template file:

Project Structure:
your_project/
├── app.py          # Flask application code
└── templates/      # Template folder
    └── index.html  # Template file

4. Use Jinja2 Syntax in Templates

In templates/index.html, embed dynamic data using Jinja2 syntax:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>{{ name }}'s Personal Homepage</title>
</head>
<body>
    <h1>Welcome to {{ name }}'s homepage!</h1>

    <!-- Variable substitution: display the name passed from the backend -->
    <p>Age: {{ age }} years old</p>

    <!-- Conditional judgment: determine if adult based on age -->
    {% if age >= 18 %}
        <p>Status: Adult</p>
    {% else %}
        <p>Status: Minor</p>
    {% endif %}

    <!-- Loop: display hobby list -->
    <h2>My Hobbies</h2>
    <ul>
        {% for hobby in hobbies %}
            <li>{{ loop.index }}. {{ hobby }}</li>  <!-- loop.index shows the sequence number -->
        {% endfor %}
    </ul>

    <!-- Conditional + loop: display article list -->
    <h2>My Articles</h2>
    <table border="1">
        <tr>
            <th>Title</th>
            <th>Author</th>
            <th>Publication Date</th>
        </tr>
        {% for post in posts %}
            <tr>
                <td>{{ post.title }}</td>
                <td>{{ post.author }}</td>
                <td>{{ post.date }}</td>
            </tr>
        {% endfor %}
    </table>

    <!-- Nested object data: determine student status -->
    {% if is_student %}
        <p>Identity: Student</p>
    {% else %}
        <p>Identity: Professional</p>
    {% endif %}
</body>
</html>

5. Run the Application and Test

Start app.py:

python app.py

Visit http://127.0.0.1:5000 to see the dynamically rendered page with Xiaoming’s information, hobby list, and article list.

III. Quick Overview of Jinja2 Core Syntax

The examples above use basic Jinja2 syntax. Here are the most common core features:

1. Variable Substitution

Use {{ variable_name }} to embed variables passed from the backend in the template. For example:

<p>Username: {{ user.name }}</p>  <!-- Backend passes a user dictionary -->
<p>Price: {{ product.price }}</p>  <!-- Backend passes a product object -->

2. Conditional Judgment (if-else)

Use {% if ... %}{% else %}{% elif %} to implement conditional logic. For example:

{% if is_logged_in %}
    <p>Welcome back!</p>
{% else %}
    <p>Please log in first</p>
{% endif %}

3. Loop Through Data (for)

Use {% for ... %} to iterate over lists, dictionaries, or other iterable objects. Common variables:
- loop.index: Current loop index (starts at 1)
- loop.first: Whether it’s the first element (boolean)
- loop.last: Whether it’s the last element (boolean)

Example to iterate over hobbies:

{% for hobby in hobbies %}
    <li>{{ hobby }}</li>
{% endfor %}

4. Filters

Jinja2 supports filters to process variables (e.g., formatting, conversion) using | to connect filter names. Examples:
- {{ name|upper }}: Convert string to uppercase
- {{ date|format('%Y-%m-%d') }}: Format date (requires Python’s datetime)
- {{ text|truncate(20) }}: Truncate long text to 20 characters

Example:

<p>Title: {{ post.title|truncate(15) }}</p>  <!-- Truncate title length -->

IV. Advanced Technique: Template Inheritance

When multiple pages exist (e.g., homepage, article page, personal center), repeating the same HTML structure (e.g., navigation bar, footer) is inefficient. Jinja2 supports template inheritance via a base template (base.html) that child templates extend and override.

1. Create Base Template (base.html)

Create base.html in the templates folder:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>{% block title %}Default Title{% endblock %}</title>
</head>
<body>
    <nav>
        <a href="/">Home</a> | <a href="/about">About</a>
    </nav>
    <main>
        {% block content %}{% endblock %}  <!-- Content block for child templates to override -->
    </main>
    <footer>© 2023 My Website</footer>
</body>
</html>

2. Child Template Inheritance (index.html)

In index.html, inherit base.html and override blocks:

{% extends "base.html" %}  <!-- Inherit from base.html -->

{% block title %}Xiaoming's Homepage{% endblock %}  <!-- Override title block -->

{% block content %}  <!-- Override content block -->
    <h1>Welcome to Xiaoming's Homepage!</h1>
    <p>This is the content inherited from base.html.</p>
{% endblock %}

V. Summary

Jinja2 simplifies frontend rendering of Flask backend data. Through variable substitution, conditional judgment, loops, and other syntax, dynamic pages are easily implemented. Template inheritance further improves code reusability, making project structures clearer.

After mastering Jinja2, explore advanced features like macros (reusable code snippets), custom filters, and functions. With practice, you’ll find template engines are a core tool connecting data and user interfaces in web development.

Tip: Beginners should start with simple examples (e.g., the personal homepage in this article), gradually try complex scenarios (e.g., rendering database query results, dynamic form data echo), and then delve into template inheritance and advanced syntax.

Xiaoye