1.為什麼需要模板引擎(template engine)?
在上面的例子中,我們檢視函式向客戶端返回一行HTML程式碼。當有大量HTML程式碼的時候,我們應該將它們都儲存在一個檔案裡面,從而讓控制器和使用者介面的分離。為了實現動態的生成HTML資料,我們需要藉助模板引擎。
Flask預設使用的模板引擎是Jinja2,它是一個功能齊全的Python模板引擎。
2.模板基本用法
2.1 建立模板
首先我們建立一些資料用於測試顯示效果:
user = {
'username': 'Grey Li',
'bio': 'A boy who loves movies and music.',
}
movies = [
{'name': 'My Neighbor Totoro', 'year': '1988'},
{'name': 'Three Colours trilogy', 'year': '1993'},
{'name': 'Forrest Gump', 'year': '1994'},
{'name': 'Perfect Blue', 'year': '1997'},
{'name': 'The Matrix', 'year': '1999'},
{'name': 'Memento', 'year': '2000'},
{'name': 'The Bucket list', 'year': '2007'},
{'name': 'Black Swan', 'year': '2010'},
{'name': 'Gone Girl', 'year': '2014'},
{'name': 'CoCo', 'year': '2017'},
]
複製程式碼
建立一個watchlist.html作為模板檔案
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>{{ user.username }}'s Watchlist</title>
</head>
<body>
<a href="{{ url_for('index') }}">← Return</a>
<h2>{{ user.username }}</h2>
{% if user.bio %}
<i>{{ user.bio }}</i>
{% else %}
<i>This user has not provided a bio.</i>
{% endif %}
{# Below is the movie list (this is comment) #}
<h5>{{ user.username }}'s Watchlist ({{ movies|length }}):</h5>
<ul>
{% for movie in movies %}
<li>{{ movie.name }} - {{ movie.year }}</li>
{% endfor %}
</ul>
</body>
</html>
複製程式碼
在上面的程式碼中,我們可以看到Jinja2常見的三種定界符:
(1) 語句
比如if判斷、for迴圈等:
{% ... %}
複製程式碼
(2) 表示式
比如字串、變數、函式呼叫等:
{{ ... }}
複製程式碼
(3) 註釋
{# ... #}
複製程式碼
2.2 渲染模板
渲染模板,就是執行模板中的程式碼,並傳入所有在模板中使用的變數。
from flask import Flask, render_template
...
@app.route('/watchlist')
def watchlist():
return render_template('watchlist.html'.user=user,movies=movies)
複製程式碼
3.模板輔助工具
3.1 上下文
模板上下文包含了很多變數,其中包括我們呼叫render_template()函式時手動傳入的變數以及Flask預設傳入的變數。
除了在渲染時傳入變數,我們也可以在模板中定義變數:
{% set navigation = [('/','Home') , ('/about','About')] %}
{% set navigation %}
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
{% endset %}
複製程式碼
3.1.1 內建上下文變數
標準模板全域性變數
變數 | 說明 |
---|---|
config | 當前的配置物件 |
request | 當前的請求物件,在已啟用的請求環境下可用 |
session | 當前的會話物件。在已啟用的請求環境下可用 |
g | 與請求繫結的全域性變數,在已啟用的請求環境下可用 |
3.1.2 自定義上下文
若多個模板都使用同一變數,那麼我們可以設定一個模板全域性變數。
Flask提供了一個app.context_processor裝飾器,用來註冊模板上下文處理函式。
@app.content_processor
def inject_foo():
foo='I am foo.'
return dict(foo=foo) #等價於 return {'foo':foo}
def inject_foo():
foo='I am foo.'
return dict(foo=foo) #等價於 return {'foo':foo}
app.content_processor(inject_foo)
使用lambda
app.content_processor(lambda: dict(foo='I am foo.'))
複製程式碼
當我們使用render_template()函式渲染任意一個模板時,所有使用@app.content_processor裝飾器註冊的模板上下文處理函式(包括Flask內建的上下文處理函式)都會被執行,這些函式的返回值會被新增到模板中。
3.2 全域性物件
3.2.1 內建全域性函式
Jinja2內建模板全域性函式
函式 | 說明 |
---|---|
range() | 和Python中的range()用法相同 |
lipsum(n=5,html=True,min=20,max=100) | 生成隨機文字,可以在測試時用來填充頁面。預設生成5段HTML文字,每段包含20-100個單詞 |
dict(**items) | 和Python中的dict()用法相同 |
Flask內建模板全域性函式
函式 | 說明 |
---|---|
url_for() | 用於生成URL的函式 |
get_flashed_messages() | 用於獲取flash訊息的函式 |
3.2.2 自定義全域性函式
@app.template_globak()
def bar():
return 'I am bar.'
複製程式碼
3.3過濾器
過濾器是一些用來修改和過濾變數值的特殊函式
{{ name|title }} #對name使用title過濾器
{% filter upper %}
This text becomes uppercase.
{% endfilter %}
複製程式碼
3.3.1 內建過濾器
3.3.2 自定義過濾器
from flask import Markup
@app.template_filter()
def musical(s):
return s+ Markup('♫')
複製程式碼
3.4 測試器
測試器是一些用來測試變數或表示式,返回布林值的特殊函式
{% if age is number %}
{{ age*365 }}
{% else %}
無效的數字。
{% endif %}
複製程式碼
3.4.1 內建測試器
3.4.2 自定義測試器
@app.template_test()
def baz(n):
if n == 'baz':
return True
return False
複製程式碼
3.5 模板環境物件
在Jinja2中,渲染行為由Jinja2.Environment類控制,所有的配置選項、上下文變數、全域性函式、過濾器和測試器都儲存在Environment例項上。所以我們可以通過它來新增自定義全域性物件、自定義過濾器和自定義測試器。
3.5.1 新增自定義全域性物件
def bar():
return 'I am bar.'
foo = 'I am foo'
app.jinja_env.globals['bar'] = bar
app.jinja_env.globals['foo'] = foo
複製程式碼
3.5.2 新增自定義過濾器
def smiling(s):
return s+ ':)'
app.jinja_env.filters['smiling']=smiling
複製程式碼
3.5.3 新增自定義測試器
def baz(n):
if n == 'baz':
return True
return Fasle
jinja_env.tests['baz']=baz複製程式碼