Jinja2 模板引擎(上):变量渲染、循环与条件判断

📂 所属阶段:第一阶段 — 破冰启航(基础篇)
🔗 相关章节:路由(Routing)艺术 · Jinja2 模板引擎(下)


1. Jinja2 是什么?

Jinja2 是 Flask 内置的模板引擎,使用 {{ }} 输出变量、{% %} 执行逻辑。

# Flask 自动在 templates/ 目录查找模板
from flask import render_template

@app.route("/")
def index():
    return render_template("index.html", title="首页", user={"name": "Alice"})

2. 基础变量渲染

2.1 简单变量

<!-- templates/index.html -->
<h1>{{ title }}</h1>
<p>{{ user.name }}</p>
<p>{{ user["email"] }}</p>

2.2 过滤器(Filters)

<p>大写:{{ name|upper }}</p>
<p>小写:{{ name|lower }}</p>
<p>首字母大写:{{ name|capitalize }}</p>
<p>默认值:{{ user.bio|default("暂无简介") }}</p>
<p>链式过滤:{{ name|upper|trim }}</p>
<p>安全 HTML(慎用!):{{ html_content|safe }}</p>
<p>字符串长度:{{ text|length }}</p>
<p>默认值(判断 None):{{ value|default("无") }}</p>
<p>数字格式化:{{ price|round(2) }}</p>

2.3 内置过滤器速查

过滤器说明示例
upper/lower大写/小写`"hello"
capitalize首字母大写`"hello"
trim去除首尾空白`" hi "
length长度`"hello"
default(value)默认值`None
safe标记为安全 HTML仅用于可信内容
striptags去除 HTML 标签`"hi"
join(val)连接列表`[1,2,3]
round(n)四舍五入`3.14159
tojson转 JSON`data

3. 条件判断

3.1 if / elif / else

{% if user.is_logged_in %}
    <p>欢迎,{{ user.name }}!</p>
    {% if user.is_admin %}
        <a href="/admin">管理后台</a>
    {% elif user.is_editor %}
        <a href="/editor">编辑后台</a>
    {% else %}
        <a href="/profile">个人中心</a>
    {% endif %}
{% else %}
    <a href="/login">登录</a>
    <a href="/register">注册</a>
{% endif %}

3.2 运算符

{% if user.age >= 18 %}
    <p>成年人</p>
{% endif %}

{% if article.category == "Python" and article.views > 1000 %}
    <span class="hot">热门文章</span>
{% endif %}

{% if user.role not in ["banned", "deleted"] %}
    <p>可以发言</p>
{% endif %}

{% if value is defined %}
    <p>变量已定义</p>
{% endif %}

{% if user is none %}
    <p>用户不存在</p>
{% endif %}

4. 循环(for 循环)

4.1 基础循环

<ul>
{% for article in articles %}
    <li>
        <a href="{{ url_for('article', id=article.id) }}">
            {{ article.title }}
        </a>
        <span>{{ article.views }} 阅读</span>
    </li>
{% endfor %}
</ul>

4.2 循环特殊变量

{% for article in articles %}
    <div class="article">
        <!-- 循环计数(从1开始)-->
        <span>第 {{ loop.index }} 篇</span>

        <!-- 判断首/尾元素 -->
        {% if loop.first %}
            <span class="badge">置顶</span>
        {% endif %}

        <!-- 反向计数 -->
        <span>剩余 {{ loop.revindex }} 篇</span>

        <!-- 总数 -->
        <span>({{ loop.length }} 篇中)</span>

        <h2>{{ article.title }}</h2>
    </div>
{% endfor %}

4.3 遍历字典

{% for key, value in user.items() %}
    <tr>
        <td>{{ key }}</td>
        <td>{{ value }}</td>
    </tr>
{% endfor %}

4.4 循环与条件结合

{% for article in articles %}
    {% if article.published %}
        <div>{{ article.title }}</div>
    {% endif %}
{% else %}
    <!-- 循环为空时执行 -->
    <p>暂无文章</p>
{% endfor %}

5. 宏(Macro)

5.1 定义宏

<!-- templates/macros.html -->

{% macro render_form_field(field) %}
    <div class="form-group">
        {{ field.label }}
        {{ field(class="form-control") }}
        {% if field.errors %}
            <small class="error">{{ field.errors[0] }}</small>
        {% endif %}
    </div>
{% endmacro %}

{% macro render_article_card(article) %}
    <div class="card">
        <h3>{{ article.title }}</h3>
        <p>{{ article.summary }}</p>
        <a href="{{ url_for('article', id=article.id) }}">阅读更多</a>
    </div>
{% endmacro %}

5.2 导入宏

<!-- templates/articles.html -->
{% from "macros.html" import render_article_card, render_form_field %}

{% for article in articles %}
    {{ render_article_card(article) }}
{% endfor %}

6. 自动转义

6.1 什么是自动转义?

<!-- Flask 默认自动转义 HTML -->
{{ "<script>alert('xss')</script>" }}
<!-- 输出:&lt;script&gt;alert...(不会被执行为 JS) -->

<!-- 取消转义(仅在信任内容时使用)-->
{{ "<b>粗体</b>"|safe }}

6.2 块级转义

{% raw %}
{# 整块内容不进行模板解析 #}
{{ this_will_be_literal }}
{% endraw %}

7. 模板中使用 Python 代码

<!-- Jinja2 支持的 Python 操作 -->

<!-- 三元表达式 -->
{{ user.name if user else "匿名用户" }}

<!-- 字符串格式化 -->
{{ "ID: %s" % user.id }}

<!-- in 操作符 -->
{% if "python" in article.tags %}
    <span>Python相关</span>
{% endif %}

<!-- 取反 -->
{% if not user.is_banned %}
    <p>可以发言</p>
{% endif %}

8. 小结

Jinja2 核心语法:

{{ variable }}          输出变量
{{ name|upper }}        过滤器
{% if cond %}           条件
{% for item in list %}  循环
{% macro name() %}      宏定义
{% include "file.html" %}包含模板
{{ url_for('func') }}   反向生成 URL
{{ session['key'] }}     访问 session
{{ request.args.get('q') }} 访问请求参数

💡 最佳实践:在模板中只做展示,不写复杂业务逻辑。复杂的计算和判断放在视图函数或自定义 Jinja2 扩展中处理。


🔗 扩展阅读