Flask 模板 - 變量、過濾器

模板

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>
複製代碼

下面來寫一個簡單的示例:函數

  1. 導入Flask使用模板的方法
from flask import render_template
複製代碼
  1. 在templates建立一個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>
</body>
</html>
複製代碼
  1. 編寫使用模板的示例代碼
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)
複製代碼
  1. 測試訪問視圖

http://127.0.0.1:5000/indexpost

能夠看到,模板成功顯示出了參數內容。可是經過上方那樣設置參數的話,不是很好。下面修改一下設置參數的方式。測試

  1. 使用字典來傳遞參數
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)
複製代碼
  1. 再次訪問index

能夠從上面看到,字典參數的傳遞是採用**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攻擊的示例。

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.頁面顯示以下

相關文章
相關標籤/搜索