Flask的視圖函數有兩個做用:處理業務邏輯和返回響應內容。html
在大型應用中,把業務邏輯和表現內容放在一塊兒,會增長代碼的複雜度和維護成本。此次的模板內容主要的做用便是承擔視圖函數的另外一個做用,即返回響應內容。flask
模板實際上是一個包含響應文本的文件,其中用佔位符(變量)表示動態部分,告訴模板引擎其具體值須要從使用的數據中獲取。使用真實值替換變量,再返回最終獲得的字符串,這個過程稱爲「渲染」。api
Flask使用Jinja2這個模板引擎來渲染模板。Jinja2能識別全部類型的變量,包括{}。 Jinja2模板引擎,Flask提供的render_template函數封裝了該模板引擎,render_template函數的第一個參數是模板的文件名,後面的參數都是鍵值對,表示模板中變量對應的真實值。bash
Jinja2官方文檔(docs.jinkan.org/docs/jinja2…)app
先來認識下模板的基本語法:xss
<title>{% block title %}{% endblock %}</title>
<ul>
{% for user in users %}
<li><a href="{{ user.url }}">{{ user.username }}</a></li>
{% endfor %}
</ul>
複製代碼
下面來寫一個簡單的示例:函數
from flask import render_template
複製代碼
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h3>name = {{ user_name }}</h3>
<h3>age = {{ age }}</h3>
</body>
</html>
複製代碼
from flask import Flask,render_template
# 建立Flask的app應用
app = Flask(__name__)
# index視圖函數
@app.route("/index")
def index():
# 設置模板html,以及設置參數
return render_template('index.html', user_name='libai', age=18 )
if __name__ == '__main__':
app.run(debug=True)
複製代碼
http://127.0.0.1:5000/indexpost
能夠看到,模板成功顯示出了參數內容。可是經過上方那樣設置參數的話,不是很好。下面修改一下設置參數的方式。測試
from flask import Flask,render_template
# 建立Flask的app應用
app = Flask(__name__)
# index視圖函數
@app.route("/index")
def index():
# 使用字典的方式傳遞參數
context = {
"user_name": 'libai',
"age": 18,
}
return render_template('index.html', **context )
if __name__ == '__main__':
app.run(debug=True)
複製代碼
能夠從上面看到,字典參數的傳遞是採用**context
的方式。ui
因此 **context
等價於 user_name=libai, age=18
的參數傳遞。
在模板中{{ variable }}
結構表示變量,是一種特殊的佔位符,告訴模板引擎這個位置的值,從渲染模板時使用的數據中獲取;Jinja2除了能識別基本類型的變量,還能識別{}; 其中模板變量能夠傳遞字典dict
,列表list
,下面再來寫幾個複雜一些的參數傳遞示例。
1. 編寫視圖函數index,設置多幾個類型參數
# index視圖函數
@app.route("/index")
def index():
# 使用字典的方式傳遞參數
context = {
"user_name": 'libai',
"age": 18,
# 傳遞字典
"my_dict" : {
"key1" : "value1",
"key2" : "value2",
},
# 傳遞list
"my_list" : [1,2,3,4,5,6],
# 傳遞int類型
"index" : 0
}
return render_template('index.html', **context )
複製代碼
2. 編寫index.html,設置多幾個參數
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h3>name = {{ user_name }}</h3>
<h3>age = {{ age }}</h3>
<!-- 使用字典參數 -->
<p>my_dict key1 = {{ my_dict["key1"] }}</p>
<p>my_dict key2 = {{ my_dict.key2 }}</p>
<!-- 使用列表list參數 -->
<p>my_list = {{ my_list }}</p>
<p>my_list[1] = {{ my_list[1] }}</p>
<p>my_list[0] = {{ my_list[0] }}</p>
<p>my_list[index] = {{ my_list[index] }}</p>
</body>
</html>
複製代碼
3. 訪問index
能夠看到無論是dict
仍是list
類型,均可以使用。
注意:在Django中模板中的變量是沒法直接相加等運算操做的,而Flask調用的模板能夠。
4. 設置模板變量執行運算
<!-- 變量運算 -->
<p>my_list[1] = {{ my_list[1] }}</p>
<p>my_list[2] = {{ my_list[2] }}</p>
<p>my_list[1] + my_list[2] = {{ my_list[1] + my_list[2] }}</p>
<p>my_list[1] - my_list[2] = {{ my_list[1] - my_list[2] }}</p>
<p>my_list[1] * my_list[2] = {{ my_list[1] * my_list[2] }}</p>
<p>my_list[1] / my_list[2] = {{ my_list[1] / my_list[2] }}</p>
<p>my_list[1] % my_list[2] = {{ my_list[1] % my_list[2] }}</p>
複製代碼
5. 訪問index,查看運算結果
能夠看出基本運算均可以執行。
safe:禁用轉義;
<p>{{ '<em>hello</em>' | safe }}</p>
複製代碼
capitalize:把變量值的首字母轉成大寫,其他字母轉小寫;
<p>{{ 'hello' | capitalize }}</p>
複製代碼
lower:把值轉成小寫;
<p>{{ 'HELLO' | lower }}</p>
複製代碼
upper:把值轉成大寫;
<p>{{ 'hello' | upper }}</p>
複製代碼
title:把值中的每一個單詞的首字母都轉成大寫;
<p>{{ 'hello' | title }}</p>
複製代碼
trim:把值的首尾空格去掉;
<p>{{ ' hello world ' | trim }}</p>
複製代碼
reverse:字符串反轉;
<p>{{ 'olleh' | reverse }}</p>
複製代碼
format:格式化輸出;
<p>{{ '%s is %d' | format('name',17) }}</p>
複製代碼
striptags:渲染以前把值中全部的HTML標籤都刪掉;
<p>{{ '<em>hello</em>' | striptags }}</p>
複製代碼
<p>{{ " hello world " | trim | upper }}</p>
複製代碼
能夠屢次使用過濾器。
first:取第一個元素
<p>{{ [1,2,3,4,5,6] | first }}</p>
複製代碼
last:取最後一個元素
<p>{{ [1,2,3,4,5,6] | last }}</p>
複製代碼
length:獲取列表長度
<p>{{ [1,2,3,4,5,6] | length }}</p>
複製代碼
sum:列表求和
<p>{{ [1,2,3,4,5,6] | sum }}</p>
複製代碼
sort:列表排序
<p>{{ [6,2,3,1,5,4] | sort }}</p>
複製代碼
下面執行一下上面的過濾器,以下:
上面展現禁用轉義safe過濾器有些簡單,下面再來一個xss攻擊的示例。
編寫一個輸入框,容許將輸入內容直接在頁面展現,查看是否會執行js代碼。
1. 編寫xss.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/xss_ex" method="post">
<label for="textarea"></label><textarea name="textarea" id="textarea" cols="30" rows="10"></textarea>
<input type="submit" value="提交">
</form>
{{ textarea }}
</body>
</html>
複製代碼
2.編寫處理xss的視圖函數
# xss視圖函數
@app.route("/xss_ex",methods=['GET','POST'])
def xss_ex():
textarea = ""
if request.method == 'POST':
textarea = request.form.get("textarea")
return render_template('xss.html', textarea=textarea)
複製代碼
3.輸入js內容,查看是否會執行js
輸入<script>alert("hello");</script>
,點擊提交
能夠看到默認js代碼並不會被執行,而是會被轉義顯示字符串。那麼若是須要執行呢?
這時候就能夠增長過濾器safe了。
4.設置禁用轉義過濾器safe
5.再次輸入內容js
此時將會執行js,若是這段js是惡意代碼,那麼就是典型的xss攻擊!
{% filter upper %}
this is a Flask Jinja2 introduction
{% endfilter %}
複製代碼
過濾器的本質是函數。當模板內置的過濾器不能知足需求,能夠自定義過濾器。自定義過濾器有兩種實現方式:一種是經過Flask應用對象的add_template_filter方法。還能夠經過裝飾器來實現自定義過濾器。
自定義的過濾器名稱若是和內置的過濾器重名,會覆蓋內置的過濾器。
實現方式一:經過調用應用程序實例的add_template_filter方法實現自定義過濾器。該方法第一個參數是函數名,第二個參數是自定義的過濾器名稱。
def filter_double_sort(ls):
return ls[::2]
app.add_template_filter(filter_double_sort,'ls_2')
複製代碼
實現方式二:用裝飾器來實現自定義過濾器。裝飾器傳入的參數是自定義的過濾器名稱。
@app.template_filter('ls3')
def filter_double_sort(ls):
return ls[::-3]
複製代碼
上面則是自定義過濾器的兩種方式,下面來執行一下這兩個自定義過濾器的示例。
1.設置兩個自定義過濾器
# 自定義過濾器:方法一
def filter_double_sort(ls):
return ls[::2]
app.add_template_filter(filter_double_sort,'ls_2')
# 自定義過濾器:方法二
@app.template_filter('ls3')
def filter_double_sort(ls):
return ls[::-3]
@app.route("/index")
def index():
# 使用字典的方式傳遞參數
context = {
# 傳遞list
"my_list" : [1,2,3,4,5,6],
}
return render_template('index.html', **context )
if __name__ == '__main__':
app.run(debug=True)
複製代碼
2.在index.html使用兩個自定義過濾器
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
自定義過濾器:
<p>{{ my_list | ls_2 }}</p>
<p>{{ my_list | ls3 }}</p>
</body>
</html>
複製代碼
3.頁面顯示以下