引言
模版是一個包含響應文本的文件,其中包含用佔位變量表示的動態部分,其具體指只在請求的上下文中才能知道。使用真實值替換變量,再返回最終得到的響應字符串,這一過程稱爲 渲染 。爲了渲染模版, Flask
使用了一個名爲 Jinja2
的強大模版引擎。
Jinja2 模版引擎
形式最簡單的Jinja2模版就是一個包含響應文本的文件。
示例 1 templates/index.html
<h1>Hello World!</h1>
示例 2 templates/user.html
<h1>Hello, {{ name }}!</h1>
示例2 中包含一個使用變量表示的動態部分 {{ name }}
渲染模版
默認情況下, Flask
在程序文件夾中的 templates
子文件夾中尋找模版。我們將 示例1 和 示例2 分別命名爲 index.html
和 user.html
存放在 templates
文件夾下。
視圖函數對應爲:
from flask import Flask, render_template
#...
@app.route('/')
def index():
return render_template('index.html')
@app.route('/user/<name>')
def user(name):
return render_template('user.html', name=name)
Flask
提供的 render_template
函數把 Jinja2
模版引擎集成到程序中。 render_template
函數的第一個參數是模版的文件名。隨後的參數都是鍵值對, 表示模版中變量對應的真實值。在這段代碼中,第二個模版收到一個名爲 name
的變量。
視圖函數中 name=name
是關鍵字參數,左邊的 name
表示參數名,就是模版中的佔位符;右邊的 name
是當前作用域中的變量,表示同名參數的值。
變量
示例2 在模版中使用的 {{ name }}
結構表示一個變量,它是一種特殊的佔位符, 告訴模版引擎這個位置的值從渲染模版時使用的數據中獲取。
Jinja2
能識別所有類型的變量,甚至 列表、字典和對象。在模版中使用變量的一些示例如下:
<p>A vakue from a dictionary: {{ mydict['key'] }}.</p>
<p>A vakue from a list: {{ mylist[3] }}.</p>
<p>A vakue from a list, with a variable index: {{ mylist[myintvar] }}.</p>
<p>A vakue from a object's method: {{ myobj.somemethod() }}.</p>
可以使用 過濾器 修改變量, 過濾器名添加在變量名之後, 中間使用豎線分隔。例如,下述模版以首字母大寫形式顯示變量 name
值:
Hello, {{ name|capitalize }}
常用過濾器:
過濾器名 | 說明 |
---|---|
safe | 渲染值時不轉義 |
capitalize | 把值的首字母轉換成大寫,其他字母轉換成小寫 |
lower | 把值轉換成小寫形式 |
upper | 把值轉換成大寫形式 |
title | 把值中的每個單詞的首字母都轉成大寫 |
trim | 把值的首尾空格去掉 |
scriptags | 渲染之前把值中所有的 HTML 標籤都刪掉 |
注意:千萬別在不可信的值上使用 safe
過濾器,例如用戶在表單中輸入的文本。
默認情況下,出於安全考慮, Jinja2
會轉移所有變量。例如, 如果一個變量的值爲 '<h1>Hello</h1>'
,Jinja2
會將其渲染成 '<h1>Hello</h1>'
,瀏覽器能顯示 h1
元素,但不會進行解釋。
控制結構
Jinja2 提供了多種控制結構,可用來改變模版的渲染流程。
條件控制語句
{% if user %}
Hello, {{ user }}
{% else %}
Hello, Stranger!
{% endif %}
for 循環
<ul>
{% for comment in comments %}
<li>{{ comment }}</li>
{% endfor %}
</ul>
宏
宏類似 python
中的函數
{% macro render_comment(comment) %}
<li>{{ comment }}</li>
{% endmacro %}
<ul>
{% for comment in comments %}
{{ render_comment(comment) }}
{% endfor %}
</ul>
包含
需要在多出重複使用的模版代碼片段可以寫入單獨的文件,再包含在所有模塊中,以避免重複:
{% include 'common.html' %}
繼承
另一種重複使用代碼的強大方式是模版集成,它類似與 Python 代碼中的類繼承。首先, 創建一個名爲 base.html 的基模版:
<html>
<head>
{% block head %}
<title>{% block title%}{% endblock %} - My Application<title>
{% endblock %}
</head>
<body>
{% block body %}
{% endblock %}
</body>
</head>
block
標籤定義的元素可在衍生模版中修改。在 base.html
中,我們定義了名爲 head
、title
和 body
的塊。注意, title
包含在 head
中。 下面這個示例是基模版的衍生模版:
{% extends "base.html" %}
{% block title %}Index{% endblock %}
{% block head %}
{{ supper() }}
<style>
</style>
{% endblock %}
{% block body %}
<h1>Hello, World!</h1>
{% endblock %}
extends
指令聲明這個模版衍生自 base.html
。在 extends
指令後, 基模版中的 3 個塊被重新定義, 模版引擎會將其插入適當的位置。注意新定義的 head
塊, 在基模版中其內容不是空的, 所以使用 super()
獲取原來的內容。