Flask 的 jinja2 模板
還記的 “第一個 Flask 程序”這一小節中我們直接在 Python 源程序中直接返回一段 HTML 字符串,就可以在瀏覽器中看到效果,但是如果我們的 HTML 特別復雜呢?我們還能使用這樣的形式嗎?
答案是不行的,如果你的 HTML 特別復雜仍然使用這樣的方法會造成你的后端程序非常的混亂,Python 代碼和 HTML 代碼混雜在一起,程序的可閱讀行非常差。
本節課我們將會使用一個叫做 Jinja2 的東西來解決上面提到的問題。
Tips:本節課所有的代碼已經上傳到了 Github,可以點擊這里進行下載。
1. 模板簡介
1.1 簡介
瀏覽器訪問網站時,服務端通常會返回一個包含各類信息的 html 頁面。因為網頁是動態的,頁面中的某些信息需要根據不同的情況來進行調整,比如對登錄和未登錄用戶顯示不同的信息,所以頁面需要在用戶訪問時根據程序邏輯動態生成。
把包含變量和運算邏輯的 html 或其他格式的文本叫做模板,執行這些變量替換和邏輯計算工作的過程被稱為渲染,在 Flask 中,這個工作由模板渲染引擎——jinja2 來完成。
1.2 一個具體的例子
以下是一個 jinja2 的模板,它對登錄和未登錄用戶顯示不同的信息:
<html>
{% if login %}
<p>你好,{{name}}</p>
{% else %}
<a href='/login'>登錄</a>
{% endif %}
</html>
如果用戶已經登錄:變量 login 為真、變量 name 為 tom,模板被渲染成如下的 html 文件:
<html>
<p>你好,tom</p>
</html>
如果用戶沒有登錄:變量 login 為假,模板被渲染成如下的 html 文件:
<html>
<a href='/login'>登錄</a>
</html>
2. 在 Flask 中使用模板
本節通過一個具體的例子講解如何在 Flask 中使用 jinja2 模板。
2.1 目錄結構
程序包含有兩個源文件: app.py
和 index.html,目錄結構如下:
app.py
是 Flask 程序,將渲染后的模板返回給瀏覽器;templates 是存放模板的目錄,它和 app.py 位于相同的目錄;templates/index.html 是模板文件。
2.2 編寫 app.py
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def index():
return render_template('index.html', name = 'tom', age = 10)
app.run(debug = True)
在第 1 行,從模塊 flask 中導入函數 render_template,該函數將 jinja2 模板渲染為 html;在第 3 行,編寫路徑 / 的處理函數 index(),調用 render_template,對模板 templates/index.html 進行渲染。
render_template 包含有 2 個命名參數:name 和 age,模板引擎將模板 templates/index.html 中的變量進行替換。
2.3 編寫模板文件 templates/index.html
<html>
<body>
<h2>My name is {{ name }}, I am {{ age }} years old</h2>
</body>
</html>
模板文件中的 {{ name }} 和 {{ age }} 被稱為 jinja2 變量。render_template 包含有兩個命名參數: name 和 age,{{ name }} 被替換為 name,{{ age }} 被替換為 age,最后渲染的 html 如下:
<html>
<body>
<h2>My name is tom, I am 10 years old</h2>
</body>
</html>
在瀏覽器中顯示如下:
3. 分界符
jinja2 模板文件混合 html 語法與 jinja2 語法,使用分界符區分 html 語法與 jinja2 語法。有 5 種常見的分界符:
- {{ 變量 }},將變量放置在 {{ 和 }} 之間;
- {% 語句 %},將語句放置在 {% 和 %} 之間;
- # 語句,將語句放置在 # 之后;
- {# 注釋 #},將注釋放置在 {# 和 #} 之間;
- ## 注釋,將注釋放置在 # 之后。
以下模板文件包含了所有常見的分界符:
<!DOCTYPE html>
<html lang="en">
<body>
{{ variable }}
<ul>
{% for item in seq %}
<li>{{ item }}</li>
{% endfor %}
</ul>
<ul>
# for item in seq
<li>{{ item }}</li>
# endfor
</ul>
{# this is comment #}
## this is comment
</body>
</html>
4. 變量
1. 語法
jinja2 模板中,使用 {{ 和 }} 包圍的標識符稱為變量,模板渲染會將其替換為 Python 中的變量,語法如下:
{{ 變量 }}
2. jinja2 模板
定義演示變量功能的模板:
<html>
{{ string }}
<ul>
<li> {{ list[0] }}
<li> {{ list[0] }}
<li> {{ list[1] }}
</ul>
<ul>
<li> {{ dict['name'] }}
<li> {{ dict['age'] }}
</ul>
</html>
包含有 3 種類型的變量:字符串、列表、字典,它們會被替換為同名的 Python 變量。
3. jinja2 的模板輸入
string = 'www.xianlaiwan.cn'
list = ['www', 'imooc', 'com']
dict = {'name': 'zhangsan', 'age': 12}
4. 渲染后的 HTML
<html>
www.xianlaiwan.cn
<ul>
<li> www
<li> www
<li> imooc
</ul>
<ul>
<li> zhangsan
<li> 12
</ul>
5. for 語句
1. 語法
jinja2 模板中,使用 {% 和 %} 包圍的語法塊稱為語句,jinja2 支持類似于 Python 的 for 循環語句,語法如下:
{% for item in iterable %}
{% endfor %}
或者
# for item in iterable
# endfor
以上兩者是等價的。
2. jinja2 模板
定義一個演示 for 循環語句功能的模板:
<h1>Members</h1>
<ul>
{% for user in users %}
<li>{{ user }}</li>
{% endfor %}
</ul>
在第 3 行,定義 for 循環語句,遍歷列表 users;在第 4 行,在循環體中使用 {{ user }} 引用當前正在被遍歷的元素。
3. jinja2 的模板輸入
users = ['tom', 'jerry', 'mike']
4. 渲染后的 HTML
<h1>Members</h1>
<ul>
<li>tom</li>
<li>jerry</li>
<li>mike</li>
</ul>
6. if 語句
1. 語法
jinja2 模板中,使用 {% 和 %} 包圍的語法塊稱為語句,jinja2 支持類似于 Python 的 if-else 判斷語句,語法如下:
{% if cond %}
{% else %}
{% endif %}
jinja2 支持類似于 Python 的 if-elif 判斷語句,語法如下:
{% if cond %}
{% elif cond %}
{% endif %}
2. jinja2 模板
定義一個演示 if 語句功能的模板:
<html>
{% if a %}
<p>a is True</p>
{% else %}
<p>a is False</p>
{% endif %}
{% if b %}
<p>b is True</p>
{% elif c %}
<p>b is False, and c is True</p>
{% endif %}
</html>
在模板中根據變量 a、b、c 的取值生成不同的內容。
3. jinja2 的模板輸入
a = False
b = False
c = True
4. 渲染后的 html
<html>
<p>a is False</p>
<p>b is False, and c is True</p>
</html>
7. 測試
1. 語法
jinja2 提供的 tests 可以用來在語句里對變量或表達式進行測試,語法如下:
{% variable is test %}
完整的 test 請參考 https://jinja.palletsprojects.com/en/master/templates/#builtin-tests,部分的 test 如下:
test 名稱 | 功能 |
---|---|
defined | 變量是否已經定義 |
boolean | 變量的類型是否是 boolean |
integer | 變量的類型是否是 integer |
float | 變量的類型是否是 float |
string | 變量是否是 string |
mapping | 變量的類型是否是字典 |
sequence | 變量的類型是否是序列 |
even | 變量是否是偶數 |
odd | 變量是否是奇數 |
lower | 變量是否是小寫 |
upper | 變量是否是大寫 |
2. jinja2 模板
定義一個演示 test 功能的模板:
<html>
{% if number is odd %}
<p> {{ number }} is odd
{% else %}
<p> {{ number }} is even
{% endif %}
{% if string is lower %}
<p> {{ string }} is lower
{% else %}
<p> {{ string }} is upper
{% endif %}
</html>
在第 2 行,number is odd 測試 number 是否為奇數;在第 8 行,string is lower 測試 string 是否為小寫。
3. jinja2 的模板輸入
number = 404
string = 'HELLO'
4. 渲染后的 html
<html>
<p> 404 is even
<p> HELLO is upper
</html>
8. 過濾器
1. 語法
jinja2 過濾器的是一個函數,語法如下:
{{ variable | filter }}
執行函數調用 filter(varialbe),把函數返回值作為這個代碼塊的值。
在詞條 “jinja2 模板過濾器的使用” 中,詳細講解過濾器,本節僅僅給出一個簡單例子。
2. jinja2 模板
<html>
{{ string | upper }}
</html>
3. jinja2 的模板輸入
string = 'hello'
4. 渲染后的 html
<html>
HELLO
</html>
9. 小結
本節講解 Flask 的默認模板語言 jinja2,通過具體的例子講解了 jinja2 中的變量、if 語句、for 語句等概念,使用思維導圖概括如下: