邊做邊學Python Flask Web開發(4)-- 使用Jinjia2模板(上)
概述
Flask中我們通常使用Jinjia2模板語言來實現複雜的頁面渲染,Jinja2 是一個現代的,設計者友好的,仿照 Django 模板的 Python 模板語言。 它速度快,被廣泛使用,並且提供了可選的沙箱模板執行環境保證安全,它的特性有:
- 沙箱中執行
- 強大的 HTML 自動轉義系統保護系統免受 XSS
- 模板繼承
- 及時編譯最優的 python 程式碼
- 可選提前編譯模板的時間
- 易於除錯。異常的行數直接指向模板中的對應行。
- 可配置的語法
一個典型的Jinja2模板
一個典型的Jinja2模板如下所示,這裡面展示瞭如何定義區塊(block),如何迭代資料,如何顯示資料。
<title>{{title}}</title>
<ul>
{% for user in users %}
<li><a href="{{ user.url }}">{{ user.username }}</a></li>
{% endfor %}
</ul>
將上述程式碼放置在當前目錄的templates目錄下面,然後在當前目錄編寫如下程式碼:
from flask import Flask,render_template
app = Flask(__name__)
@app.route('/hello')
def hello():
users = [{"username":"users1" ,"url":"/users/user1"},
{"username":"users2","url":"/users/user2"}]
return render_template("hello.html",title="User List",users=users)
if __name__ == '__main__':
app.run(debug=True)
在Flask中使用模板
Flask可以在檢視中或錯誤處理函式中使用模板渲染的功能。在Flask中渲染Jinja2模板非常簡單,上面就是一個典型的例子。使用from flask import render_template
render_template("模板檔案",引數1,引數2...)
預設情況下,Flask會在包含app = Flask(_name_)的原始碼目錄下的templates目錄中查詢“模板檔案”,我們的教程中,如果沒有特別說明,app在檢視檔案中生成,如果檢視函式中出現render_template(“index.html”)語句,Flask會在檢視所在目錄下的templates目錄中查詢index.html。我們也可以在templates目錄中按照自己的業務邏輯設定子目錄,這樣的話渲染函式看起來可能是這樣的:render_template(“user/list.html”)。
如果你不想把模板放在預設的templates目錄下,可以在生成app物件的時候指定一個引數使用自己的模板目錄:
app = Flask(__name__,template_folder='tpl')
基本的模板用法
顯示
顯示各類Python支援的資料是模板的最基本用法。
字串/數字
字串和數字是最基本的資料型別,可以使用一對雙大括號顯示此類資料,例如
<title>{{title}}</title>
列表
列表型別的資料我們需使用一個for迴圈對資料進行迭代,例如:
{% for user in users %}
<li>{{ user }}</a></li>
{% endfor %}
上面的程式碼通過for語句和endfor構成了一個程式碼塊,程式碼塊中的所有內容(包括HTML和變數值)都會根據迭代的數量多次生成。
字典
字典可以使用點操作符或者下標訪問的方式取得值。例如:
Username:{{ user['name'] }}
Email: {{ user.email }}
如果元素的key沒有在字典中找到,Jinja2通常不會丟擲異常,這點在除錯的時候需要格外注意,在沒有顯示資料時你要自己弄清楚是缺少key,還是該key對應的值是空。
物件
嚴格的說,上面介紹的幾種資料型別在Python中也是以物件的形式存在的,所以本質上說模板中使用常用的資料型別和使用自定義物件是一回事。假設我們向模板傳遞了一個名稱是obj的物件,它有一個屬性name,有一個方法say,在模板中使用類似下面的程式碼分別去訪問其屬性和方法。
<h5>{{obj.name}}:</h5>
<p>{{obj.say()}}</p>
迴圈
迴圈通常用來顯示一個可迭代的物件,例如上文中使用迴圈展示一個列表中的全部內容。常見的資料型別中除了列表,字典也可以使用for迴圈進行迭代。生成一個列表或者具有多行資料的表格是迴圈常見的用法,比如:
<h1>Members</h1>
<ul>
{% for user in users %}
<li>{{ user.username }}</li>
{% endfor %}
</ul>
可以使用sort過濾器為迭代排序(預設的排序規則是字母順序或數值順序),針對一些簡單的資料型別(如字串或數字構成的列表、簡單的key:value型的字典)我們直接這樣去使用它:
{% for item in [4,2,1,3]|sort() %}
{{item}}
{% endfor %}
可以使用reverse=True指定按照倒序排列。
{% for k,v in {"key3":3,"key2":2,"key1":1}.items()|sort(reverse=True) %}
{{k}}:{{v}}
{% endfor %}
針對一些複雜的物件,我們可以使用attribute=’?’指定按照某個屬性排序,比較常見的是由字典構成的列表,下面的例子按照字典中的email進行排序:
{% for item in [{"username":"wang","email":"[email protected]"},
{"username":"chen","email":"[email protected]"},
{"username":"guo","email":"[email protected]"}]|sort(attribute='email') %}
{{item.username}}
{% endfor %}
Jinjia2為迴圈內建了一個非常有用的特殊物件loop,可以在迴圈內部的程式碼塊中呼叫。例如下面的程式碼可以在表格中顯示一個從1開始的序號:
<h1>Members</h1>
<table>
<th>
<td>Sequnce</td>
<td>Username</td>
</th>
{% for user in users %}
<tr>
<td>loop.index</td>
<td>{{ user.username }}</td>
</tr>
{% endfor %}
</table>
loop物件的詳細說明見下表。
屬性值 | 描述 |
---|---|
loop.index | 當前迭代的索引,從1開始算 |
loop.index0 | 當前迭代的索引,從0開始算 |
loop.revindex | 相對於序列末尾的索引,從1開始算 |
loop.revindex0 | 相對於序列末尾的索引,從0開始算 |
loop.first | 相當於 loop.index == 1. |
loop.last | 相當於 loop.index == len(seq) - 1 |
loop.length | 序列的長度. |
loop.cycle | 可以接受兩個字串引數,如果當前迴圈索引是偶數,則顯示第一個字串,是奇數則顯示第二個字串。 |
loop.cycle常被在表格中用來用不同的背景色區分相鄰的行。例如:
{% for row in rows %}
<li class="{{ loop.cycle('odd', 'even') }}">{{ row }}</li>
{% endfor %}
需要注意的是,Jinja的迴圈不支援break和continue標記。你可以對需要迭代的sequence使用過濾器來達到與break和continue相同的目的。
下面的例子中,如果user.hidden屬性為true的則continue
{% for user in users if not user.hidden %}
<li>{{ user.username|e }}</li>
{% endfor %}
Jinja的for語句有一個和python相同的用法,那就是else:當被迭代的物件元素個數為0時顯示else中的內容,如下例:
<ul>
{% for user in users %}
<li>{{ user.username|e }}</li>
{% else %}
<li><em>no users found</em></li>
{% endif %}
</ul>
判斷
同大多資料程式語言一樣,Jinja2的判斷使用if語句實現,比較常見的用法是判斷一個變數是否已定義,是否非空,是否為true。if的用法比較簡單,舉個例子向大家說明一下:
{% if users %}
<ul>
{% for user in users %}
<li>{{ user.username|e }}</li>
{% endfor %}
</ul>
{% endif %}
和python一樣,也可以使用elif和else
{% if kenny.sick %}
Kenny is sick.
{% elif kenny.dead %}
You killed Kenny! You bastard!!!
{% else %}
Kenny looks okay --- so far
{% endif %}