在一般的 Web 程式裡,訪問一個地址通常會返回一個包含各類資訊的 HTML 頁面。因為我們的程式是動態的,頁面中的某些資訊需要根據不同的情況來進行調整,比如對登入和未登入使用者顯示不同的資訊,所以頁面需要在使用者訪問時根據程式邏輯動態生成。
我們把包含變數和運算邏輯的 HTML 或其他格式的文字叫做模板,執行這些變數替換和邏輯計算工作的過程被稱為渲染,這個工作由我們這一章要學習使用的模板渲染引擎——Jinja2 來完成。
按照預設的設定,Flask 會從程式例項所在模組同級目錄的 templates 資料夾中尋找模板,我們的程式目前儲存在專案根目錄的 app.py 檔案裡,所以我們要在專案根目錄建立這個資料夾:
$ mkdir templates複製程式碼
模板基本語法
在社交網站上,每個人都有一個主頁,藉助 Jinja2 就可以寫出一個通用的模板:
<h1>{{ username }}的個人主頁</h1>
{% if bio %}
<p>{{ bio }}</p> {# 這裡的縮排只是為了可讀性,不是必須的 #}
{% else %}
<p>自我介紹為空。</p>
{% endif %} {# 大部分 Jinja 語句都需要宣告關閉 #}複製程式碼
Jinja2 的語法和 Python 大致相同,你在後面會陸續接觸到一些常見的用法。在模板裡,你需要新增特定的定界符將 Jinja2 語句和變數標記出來,下面是三種常用的定界符:
{{ ... }}
用來標記變數。{% ... %}
用來標記語句,比如 if 語句,for 語句等。{# ... #}
用來寫註釋。
模板中使用的變數需要在渲染的時候傳遞進去,具體我們後面會了解。
編寫主頁模板
我們先在 templates 目錄下建立一個 index.html 檔案,作為主頁模板。主頁需要顯示電影條目列表和個人資訊,程式碼如下所示:
templates/index.html:主頁模板
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>{{ name }}'s Watchlist</title>
</head>
<body>
<h2>{{ name }}'s Watchlist</h2>
{# 使用 length 過濾器獲取 movies 變數的長度 #}
<p>{{ movies|length }} Titles</p>
<ul>
{% for movie in movies %} {# 迭代 movies 變數 #}
<li>{{ movie.title }} - {{ movie.year }}</li> {# 等同於 movie['title'] #}
{% endfor %} {# 使用 endfor 標籤結束 for 語句 #}
</ul>
<footer>
<small>© 2018 <a href="http://helloflask.com/tutorial">HelloFlask</a></small>
</footer>
</body>
</html>複製程式碼
為了方便對變數進行處理,Jinja2 提供了一些過濾器,語法形式如下:
{{ 變數|過濾器 }}複製程式碼
左側是變數,右側是過濾器名。比如,上面的模板裡使用 length
過濾器來獲取 movies
的長度,類似 Python 裡的 len()
函式。
提示 訪問 http://jinja.pocoo.org/docs/2.10/templates/#list-of-builtin-filters 檢視所有可用的過濾器。
準備虛擬資料
為了模擬頁面渲染,我們需要先建立一些虛擬資料,用來填充頁面內容:
app.py:定義虛擬資料
name = 'Grey Li'
movies = [
{'title': 'My Neighbor Totoro', 'year': '1988'},
{'title': 'Dead Poets Society', 'year': '1989'},
{'title': 'A Perfect World', 'year': '1993'},
{'title': 'Leon', 'year': '1994'},
{'title': 'Mahjong', 'year': '1996'},
{'title': 'Swallowtail Butterfly', 'year': '1996'},
{'title': 'King of Comedy', 'year': '1999'},
{'title': 'Devils on the Doorstep', 'year': '1999'},
{'title': 'WALL-E', 'year': '2008'},
{'title': 'The Pork of Music', 'year': '2012'},
]複製程式碼
渲染主頁模板
使用 render_template()
函式可以把模板渲染出來,必須傳入的引數為模板檔名(相對於 templates 根目錄的檔案路徑),這裡即 'index.html'
。為了讓模板正確渲染,我們還要把模板內部使用的變數通過關鍵字引數傳入這個函式,如下所示:
app.py:返回渲染好的模板作為響應
from flask import Flask, render_template
# ...
@app.route('/')
def index():
return render_template('index.html', name=name, movies=movies)複製程式碼
為了更好的表示這個檢視函式的作用,我們把原來的函式名 hello
改為 index
,意思是“索引”,即主頁。
在傳入 render_template()
函式的關鍵字引數中,左邊的 movies
是模板中使用的變數名稱,右邊的 movies
則是該變數指向的實際物件。這裡傳入模板的 name
是字串,movies
是列表,但能夠在模板裡使用的不只這兩種 Python 資料結構,你也可以傳入元組、字典、函式等。
render_template()
函式在呼叫時會識別並執行 index.html 裡所有的 Jinja2 語句,返回渲染好的模板內容。在返回的頁面中,變數會被替換為實際的值(包括定界符),語句(及定界符)則會在執行後被移除(註釋也會一併移除)。
現在訪問 http://localhost:5000/ 看到的程式主頁如下圖所示:
本章小結
這一章我們編寫了一個簡單的主頁。結束前,讓我們提交程式碼:
$ git add .
$ git commit -m "Add index page"
$ git push複製程式碼
提示 你可以在 GitHub 上檢視本書示例程式的對應 commit:17b579d
進階提示
- 使用 Faker 可以實現自動生成虛擬資料,它支援豐富的資料型別,比如時間、人名、地名、隨機字元等等……
- 除了過濾器,Jinja2 還在模板中提供了一些測試器、全域性函式可以使用;除此之外,還有更豐富的控制結構支援,有一些我們會在後面學習到,更多的內容則可以訪問 Jinja2 文件學習。
- 如果你是《Flask Web 開發實戰》的讀者,模板相關內容可以在第 3 章《模板》找到,Faker 相關內容可以在第 7 章找到。