Flask模板引擎Jinja2:从基础语法到页面渲染

一、什么是Jinja2模板引擎?

在Web开发中,我们常常需要将动态数据(比如从数据库获取的用户信息、文章列表)和静态页面(HTML)结合起来,生成最终的网页。模板引擎就是用来解决这个问题的工具——它允许我们在HTML中嵌入代码逻辑,动态生成内容。

Flask框架默认使用Jinja2作为模板引擎,它是一个功能强大且语法简洁的Python模板引擎。Jinja2支持变量、条件判断、循环、模板继承等特性,能让我们更高效地编写可复用、易维护的模板代码。

二、Jinja2基础语法

1. 变量与表达式

模板中最基础的操作是显示变量。使用{{ 变量名 }}语法嵌入变量,变量由视图函数(Python代码)传递给模板。

示例
假设在视图函数中定义了变量username = "小明",在模板中这样写:

<p>欢迎,{{ username }}!</p>

渲染后会输出:欢迎,小明!

变量可以是字符串、数字、列表、字典等,也可以访问其属性或索引:

<!-- 字典 -->
<p>{{ user.age }}</p>  <!-- user是字典,输出user的age值 -->
<!-- 列表 -->
<p>{{ users[0] }}</p> <!-- users是列表,输出第一个元素 -->

2. 控制结构:条件与循环

Jinja2支持条件判断和循环,让模板能根据不同情况动态渲染内容。

条件判断(if-else)

{% if is_login %}
    <p>欢迎回来!</p>
{% else %}
    <p>请先登录</p>
{% endif %}

循环(for)
遍历列表或字典时使用{% for %},并通过loop变量获取循环状态(如是否为第一个元素、总长度等):

<ul>
    {% for item in todo_list %}
        <li>
            {{ loop.index }}. {{ item }}
            {% if loop.last %}  <!-- 判断是否为最后一个元素 -->
                <small>(这是最后一项)</small>
            {% endif %}
        </li>
    {% endfor %}
</ul>

如果循环的列表为空,可通过{% else %}显示默认内容:

{% for item in todo_list %}
    <li>{{ item }}</li>
{% else %}
    <p>列表为空</p>
{% endfor %}

3. 模板继承与包含

为了避免重复代码,Jinja2提供模板继承模板包含功能。

模板继承(Extend)
- 定义一个父模板(如base.html),包含通用结构(头部、底部、导航栏)。
- 子模板通过{% extends "base.html" %}继承父模板,并覆盖需要修改的部分。

父模板(base.html)

<!DOCTYPE html>
<html>
<head>
    <title>{% block title %}默认标题{% endblock %}</title>
</head>
<body>
    <header>
        {% block header %}<h1>网站头部</h1>{% endblock %}
    </header>
    <main>
        {% block content %}{% endblock %}
    </main>
    <footer>
        {% block footer %}<p>网站底部</p>{% endblock %}
    </footer>
</body>
</html>

子模板(index.html)

{% extends "base.html" %}  <!-- 继承父模板 -->

{% block title %}首页{% endblock %}  <!-- 覆盖title块 -->

{% block content %}  <!-- 覆盖content块 -->
    <p>这是首页内容</p>
    <ul>
        <li>项目1</li>
        <li>项目2</li>
    </ul>
{% endblock %}

模板包含(Include)
将其他模板片段(如头部、底部)直接插入当前模板,用于复用通用代码:

<!-- 在子模板中包含header.html -->
{% include "header.html" %}

4. 过滤器:处理变量

过滤器(Filter)用于对变量进行加工(如大小写转换、截断文本等),使用|符号连接。

常用过滤器
- upper/lower:转大写/小写
{{ name|upper }} → 输出NAME
- capitalize:首字母大写
{{ name|capitalize }} → 输出Name
- truncate(n):截断文本(保留前n个字符)
{{ long_text|truncate(20) }} → 截断长文本为前20字符
- safe:禁用HTML转义(谨慎使用,防止XSS攻击)
{{ raw_html|safe }} → 直接渲染HTML代码

示例

<p>{{ "hello"|upper }}</p>  <!-- 输出HELLO -->
<p>{{ "123"|int + 456 }}</p>  <!-- 转换为整数后相加 -->
<p>{{ "Flask is great!"|truncate(10) }}</p>  <!-- 截断为前10字符:Flask is gr -->

三、Flask与Jinja2的结合使用

1. 模板文件结构

Flask默认从项目根目录下的templates文件夹加载模板文件。项目结构示例:

myapp/
├── app.py
└── templates/
    ├── base.html
    ├── index.html
    └── user.html

2. 渲染模板的核心函数

视图函数通过render_template函数渲染模板,并传递变量:

from flask import Flask, render_template

app = Flask(__name__)

@app.route('/')
def index():
    # 准备数据
    users = [
        {"name": "Alice", "age": 25},
        {"name": "Bob", "age": 30}
    ]
    return render_template('index.html', users=users)  # 传递users到模板

if __name__ == '__main__':
    app.run(debug=True)

3. 完整示例:用户列表页面

模板文件(templates/user_list.html)

{% extends "base.html" %}  <!-- 继承base.html -->

{% block content %}
    <h1>用户列表</h1>
    <ul>
        {% for user in users %}  <!-- 遍历users列表 -->
            <li>
                {{ loop.index }}. {{ user.name }} ({{ user.age }}岁)
                {% if user.age > 28 %}
                    <span style="color:red;">(已成年)</span>
                {% endif %}
            </li>
        {% else %}
            <p>暂无用户</p>
        {% endfor %}
    </ul>
{% endblock %}

视图函数(app.py)

from flask import Flask, render_template

app = Flask(__name__)

@app.route('/users')
def user_list():
    # 模拟数据库查询结果
    user_data = [
        {"name": "Alice", "age": 25},
        {"name": "Bob", "age": 30},
        {"name": "Charlie", "age": 22}
    ]
    return render_template('user_list.html', users=user_data)  # 传递数据到模板

if __name__ == '__main__':
    app.run(debug=True)

四、总结与学习建议

Jinja2是Flask的核心组件,掌握其语法能极大提升Web开发效率。重点需掌握:
1. 变量与表达式{{ variable }}
2. 控制结构if-elsefor循环
3. 模板复用:继承(extends)和包含(include
4. 过滤器|符号处理变量

建议通过以下方式实践:
- 搭建一个简单的个人博客,使用模板继承实现导航栏复用
- 练习循环展示文章列表,结合过滤器截断长文本
- 尝试使用safe过滤器渲染富文本内容

通过多写多练,你会逐渐熟悉Jinja2的灵活语法,让你的Flask应用更优雅、更高效!

小夜