Flask入門學習---初步瞭解模板

Singgle發表於2019-05-06

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') }}">&larr; 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('&#9835;')
複製程式碼

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複製程式碼

相關文章