Flask 的 jinja2 模板
還記的 “第一個 Flask 程序”這一小節(jié)中我們直接在 Python 源程序中直接返回一段 HTML 字符串,就可以在瀏覽器中看到效果,但是如果我們的 HTML 特別復(fù)雜呢?我們還能使用這樣的形式嗎?
答案是不行的,如果你的 HTML 特別復(fù)雜仍然使用這樣的方法會造成你的后端程序非常的混亂,Python 代碼和 HTML 代碼混雜在一起,程序的可閱讀行非常差。
本節(jié)課我們將會使用一個叫做 Jinja2 的東西來解決上面提到的問題。
Tips:本節(jié)課所有的代碼已經(jīng)上傳到了 Github,可以點(diǎn)擊這里進(jìn)行下載。
1. 模板簡介
1.1 簡介
瀏覽器訪問網(wǎng)站時,服務(wù)端通常會返回一個包含各類信息的 html 頁面。因?yàn)榫W(wǎng)頁是動態(tài)的,頁面中的某些信息需要根據(jù)不同的情況來進(jìn)行調(diào)整,比如對登錄和未登錄用戶顯示不同的信息,所以頁面需要在用戶訪問時根據(jù)程序邏輯動態(tài)生成。
把包含變量和運(yùn)算邏輯的 html 或其他格式的文本叫做模板,執(zhí)行這些變量替換和邏輯計(jì)算工作的過程被稱為渲染,在 Flask 中,這個工作由模板渲染引擎——jinja2 來完成。
1.2 一個具體的例子
以下是一個 jinja2 的模板,它對登錄和未登錄用戶顯示不同的信息:
<html>
{% if login %}
<p>你好,{{name}}</p>
{% else %}
<a href='/login'>登錄</a>
{% endif %}
</html>
如果用戶已經(jīng)登錄:變量 login 為真、變量 name 為 tom,模板被渲染成如下的 html 文件:
<html>
<p>你好,tom</p>
</html>
如果用戶沒有登錄:變量 login 為假,模板被渲染成如下的 html 文件:
<html>
<a href='/login'>登錄</a>
</html>
2. 在 Flask 中使用模板
本節(jié)通過一個具體的例子講解如何在 Flask 中使用 jinja2 模板。
2.1 目錄結(jié)構(gòu)
程序包含有兩個源文件: app.py
和 index.html,目錄結(jié)構(gòu)如下:
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 中導(dǎo)入函數(shù) render_template,該函數(shù)將 jinja2 模板渲染為 html;在第 3 行,編寫路徑 / 的處理函數(shù) index(),調(diào)用 render_template,對模板 templates/index.html 進(jìn)行渲染。
render_template 包含有 2 個命名參數(shù):name 和 age,模板引擎將模板 templates/index.html 中的變量進(jìn)行替換。
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 包含有兩個命名參數(shù): 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 語法,使用分界符區(qū)分 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 模板中,使用 {{ 和 }} 包圍的標(biāo)識符稱為變量,模板渲染會將其替換為 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 = 'idcbgp.cn'
list = ['www', 'imooc', 'com']
dict = {'name': 'zhangsan', 'age': 12}
4. 渲染后的 HTML
<html>
idcbgp.cn
<ul>
<li> www
<li> www
<li> imooc
</ul>
<ul>
<li> zhangsan
<li> 12
</ul>
5. for 語句
1. 語法
jinja2 模板中,使用 {% 和 %} 包圍的語法塊稱為語句,jinja2 支持類似于 Python 的 for 循環(huán)語句,語法如下:
{% for item in iterable %}
{% endfor %}
或者
# for item in iterable
# endfor
以上兩者是等價的。
2. jinja2 模板
定義一個演示 for 循環(huán)語句功能的模板:
<h1>Members</h1>
<ul>
{% for user in users %}
<li>{{ user }}</li>
{% endfor %}
</ul>
在第 3 行,定義 for 循環(huán)語句,遍歷列表 users;在第 4 行,在循環(huán)體中使用 {{ user }} 引用當(dāng)前正在被遍歷的元素。
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>
在模板中根據(jù)變量 a、b、c 的取值生成不同的內(nèi)容。
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 可以用來在語句里對變量或表達(dá)式進(jìn)行測試,語法如下:
{% variable is test %}
完整的 test 請參考 https://jinja.palletsprojects.com/en/master/templates/#builtin-tests,部分的 test 如下:
test 名稱 | 功能 |
---|---|
defined | 變量是否已經(jīng)定義 |
boolean | 變量的類型是否是 boolean |
integer | 變量的類型是否是 integer |
float | 變量的類型是否是 float |
string | 變量是否是 string |
mapping | 變量的類型是否是字典 |
sequence | 變量的類型是否是序列 |
even | 變量是否是偶數(shù) |
odd | 變量是否是奇數(shù) |
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 是否為奇數(shù);在第 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 過濾器的是一個函數(shù),語法如下:
{{ variable | filter }}
執(zhí)行函數(shù)調(diào)用 filter(varialbe),把函數(shù)返回值作為這個代碼塊的值。
在詞條 “jinja2 模板過濾器的使用” 中,詳細(xì)講解過濾器,本節(jié)僅僅給出一個簡單例子。
2. jinja2 模板
<html>
{{ string | upper }}
</html>
3. jinja2 的模板輸入
string = 'hello'
4. 渲染后的 html
<html>
HELLO
</html>
9. 小結(jié)
本節(jié)講解 Flask 的默認(rèn)模板語言 jinja2,通過具體的例子講解了 jinja2 中的變量、if 語句、for 語句等概念,使用思維導(dǎo)圖概括如下: