Flask Template ( 模板學習)
阿新 • • 發佈:2019-01-02
學習目標
基本使用
過濾器&自定義過濾器
控制程式碼塊
巨集、繼承、包含
Flask 的模板中特有變數和方法
CSRF
Jinja2模板引擎簡介(template)
模板
檢視函式的主要作用是生成請求的響應,這是最簡單的請求。實際上,檢視函式有兩個作用:處理業務邏輯和返回響應內容。在大型應用中,把業務邏輯和表現內容放在一起,會增加程式碼的複雜度和維護成本。本節學到的模板,它的作用即是承擔檢視函式的另一個作用,即返回響應內容。
模板其實是一個包含響應文字的檔案,其中用佔位符(變數)表示動態部分,告訴模板引擎其具體的值需要從使用的資料中獲取 使用真實值替換變數,再返回最終得到的字串,這個過程稱為“渲染” Flask是使用 Jinja2 這個模板引擎來渲染模板
使用模板的好處:
檢視函式只負責業務邏輯和資料處理(業務邏輯方面)
而模板則取到檢視函式的資料結果進行展示(檢視展示方面)
程式碼結構清晰,耦合度低
Jinja2
兩個概念:
Jinja2:是 Python 下一個被廣泛應用的模板引擎,是由Python實現的模板語言,他的設計思想來源於 Django 的模板引擎,並擴充套件了其語法和一系列強大的功能,其是Flask內建的模板語言。
模板語言:是一種被設計來自動生成文件的簡單文字格式,在模板語言中,一般都會把一些變數傳給模板,替換模板的特定位置上預先定義好的佔位變數名。
官方文件
渲染模版函式
Flask提供的 render_template 函式封裝了該模板引擎 render_template 函式的第一個引數是模板的檔名,後面的引數都是鍵值對,表示模板中變數對應的真實值。
使用
{{}} 來表示變數名,這種 {{}} 語法叫做變數程式碼塊
<h1>{{ post.title }}</h1>
Jinja2 模版中的變數程式碼塊可以是任意 Python 型別或者物件,只要它能夠被 Python 的 str() 方法轉換為一個字串就可以,比如,可以通過下面的方式顯示一個字典或者列表中的某個元素:
{{your_dict['key']}}{{your_list[0]}}
用 {%%} 定義的控制程式碼塊,可以實現一些語言層次的功能,比如迴圈或者if語句
{% if user %}{{ user }}{% else %}
hello!
<ul >
{% for index in indexs %}
<li> {{ index }} </li>
{% endfor %}
</ul>
註釋
使用 {# #} 進行註釋,註釋的內容不會在html中被渲染出來
{# {{ name }} #}
模板使用
#.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>{{title | reverse | upper}}</h1>
<br>
{{list2 | listreverse}}
<br>
<ul>
{% for item in my_list %}
<li>{{item.id}}----{{item.value}}</li>
{% endfor %}
</ul>
{% for item in my_list %}{% if loop.index==1 %}
<li style="background-color: red;">{{ loop.index }}--{{ item.get('value') }}</li>
{% elif loop.index==2 %}
<li style="background-color: blue;">{{ loop.index }}--{{ item.get('value') }}</li>
{% elif loop.index==3 %}
<li style="background-color: green;">{{ loop.index }}--{{ item.get('value') }}</li>
{% else %}
<li style="background-color: yellow;">{{ loop.index }}--{{ item.get('value') }}</li>
{% endif %}{% endfor %}
</body>
</html>
# .py
from flask import Flask
from flask import render_template
app = Flask(__name__)
@app.route('/')
def index():
list1 = list(range(10))
my_list = [{"id": 1, "value": "我愛工作"},
{"id": 2, "value": "工作使人快樂"},
{"id": 3, "value": "沉迷於工作無法自拔"},
{"id": 4, "value": "日漸消瘦"},
{"id": 5, "value": "以夢為馬,越騎越傻"}]
return render_template(
# 渲染模板語言
'index.html',
title='hello world',
list2=list1,
my_list=my_list
)
# step1 定義過濾器
def do_listreverse(li):
temp_li = list(li)
temp_li.reverse()
return temp_li
# step2 新增自定義過濾器
app.add_template_filter(do_listreverse, 'listreverse')
if __name__ == '__main__':
app.run(debug=True)
過濾器
過濾器的本質就是函式。有時候我們不僅僅只是需要輸出變數的值,我們還需要修改變數的顯示,甚至格式化、運算等等,而在模板中是不能直接呼叫 Python 中的某些方法,那麼這就用到了過濾器。
鏈式呼叫
{{ "hello world" | reverse | upper }}
常見內建過濾器
字串操作
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>
reverse:字串反轉
<p>{{ 'olleh' | reverse }}</p>
format:格式化輸出
<p>{{ '%s is %d' | format('name',17) }}</p>
striptags:渲染之前把值中所有的HTML標籤都刪掉
<p>{{ '<em>hello</em>' | striptags }}</p>
truncate: 字串截斷
<p>{{ 'hello every one' | truncate(9)}}</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>
語句塊操作
{% filter upper %}
#一大堆文字#
{% endfilter %}
自定義過濾器
from flask import Flask
from flask import render_template
app = Flask(__name__)
@app.route('/')
def index():
list1 = list(range(10))
my_list = [{"id": 1, "value": "我愛工作"},
{"id": 2, "value": "工作使人快樂"},
{"id": 3, "value": "沉迷於工作無法自拔"},
{"id": 4, "value": "日漸消瘦"},
{"id": 5, "value": "以夢為馬,越騎越傻"}]
return render_template(
# 渲染模板語言
'index.html',
title='hello world',
list2=list1,
my_list=my_list
)
# step1 定義過濾器
def do_listreverse(li):
temp_li = list(li)
temp_li.reverse()
return temp_li
# step2 新增自定義過濾器
app.add_template_filter(do_listreverse, 'listreverse')
if __name__ == '__main__':
app.run(debug=True)
控制程式碼塊
控制程式碼塊主要包含兩個:
- if/else if /else / endif
- for / endfor
條件語句
{% if comments | length > 0 %}
There are {{ comments | length }} comments
{% else %}
There are no comments
{% endif %}
迴圈語句
{% for post in posts %}
<div>
<h1>{{ post.title }}</h1>
<p>{{ post.text | safe }}</p>
</div>
{% endfor %}
結合使用
模擬continue功能
{% for post in posts if post.text %}
<div>
<h1>{{ post.title }}</h1>
<p>{{ post.text | safe }}</p>
</div>
{% endfor %}
程式碼複用
巨集 —- 類似python中的函式
建立:
{% macro 標籤名(key=value)%} {% end macro %}
# d8_macro1.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!-- step1 巨集匯入 import filename as xx-->
{% import 'd8_macro2.html' as fun %}
<!-- step2 巨集呼叫 類似於python函式呼叫 -->
{{ fun.input('button','zhuce') }}
</body>
</html>
# d8_macro2.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!-- step1 巨集匯入 import filename as xx-->
{% import 'd8_macro2.html' as fun %}
<!-- step2 巨集呼叫 類似於python函式呼叫 -->
{{ fun.input('button','zhuce') }}
</body>
</html>
繼承
關鍵字: block extends
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>top123 {{ title }}</h1><br>
<!-- 預留空間 給繼承的html -->
{% block body %}{% endblock %}
<br><h1>bottom</h1>
</body>
</html>
{% extends 'd1_base.html' %}{% block body %}
<h2>detail</h2>
{% endblock %}
繼承:常常用於上下部分不做修改的網址
包含
包含: 將一個模板載入到另一個模板裡面種
<h1>這是一個多頁面共同的內容</h1>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!-- 特殊的自定義 函式 -->
<h1>{{ request.url }}</h1>
<h2>{{ g.title }}</h2>
index
<br>
<!-- include 呼叫html檔案 -->
{% include 'd2_include.html' %}
<hr>
<!-- 已經內建的特殊變數 -->
{{ url_for('detail') }}<br>
<a href="{{ url_for('detail') }}">詳細頁面</a>
</body>
</html>
總結:
巨集(Macro)、繼承(Block)、包含(include)均能實現程式碼的複用。
繼承(Block)的本質是程式碼替換,一般用來實現多個頁面中重複不變的區域。
巨集(Macro)的功能類似函式,可以傳入引數,需要定義、呼叫。
包含(include)是直接將目標模板檔案整個渲染出來。
crsf 跨域請求偽造
1.能夠描述出這是一種什麼樣的攻擊方式
a. 訪問A時進行了登入
b. A進行了狀態保持
c. 訪問網站B
d. 返回攻擊程式碼
e. 向網站A發起請求 在使用者未意識到的情況下
2.如何防止這種攻擊?
1.修改操作 由get操作 改為 post方式
資料修改 get ==》 post
跨網站 借用使用者資訊 訪問目標網站
2.口令驗證 隨機產生
隨機產生一個口令 拿這個口令做對比
安裝包 pip install flask-wtf
3.作為開發人員如何防止這樣的攻擊
1.設定加密欄位
app.secret_key('fad')
2.引入類
from flask_wtf.csrf import CRSFProtect
3.建立物件
CRSFProtect(app)
4.在模板的form中生成一個隨機的口令值
<input type="hidden" name="crsf_token" value="{{csrf_token()}}">
4.知道實現程式碼 背後做了什麼
註冊了請求勾子before_request 這個函式會在檢視函式前執行 進行口令驗證
如何驗證? 接收表單傳遞的口令 與session的口令對比
CRSFProtect === init === init_app ==== crsf_protect === protect === saft_str_cmp(session[filed_name], token)
session中的值是什麼時候寫 在呼叫csrf_token()函式時
from flask import Flask, render_template
app = Flask(__name__)
# 1 設定加密字串
app.secret_key = 'python'
# 2. 引入類
from flask_wtf.csrf import CSRFProtect
# 3. 建立物件
CSRFProtect(app)
@app.route("/")
def index():
return render_template('d3_index.html')
@app.route("/detail", methods=['POST'])
def detail():
return 'ok'
if __name__ == '__main__':
app.run()