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應用更優雅、更高效!

小夜