Flask-模板
阿新 • • 發佈:2020-10-05
一、cookie
- 解釋: 用來保持伺服器和瀏覽器互動的狀態的, 由伺服器設定,儲存在瀏覽器
- 作用: 用來做廣告推送
- cookie的設定和獲取
- 設定cookie: response.set_cookie(key,value,max_age)
- max_age: 表示cookie在瀏覽器的儲存時間,單位是秒
- 獲取cookie: request.cookies.get("key")
- 設定cookie: response.set_cookie(key,value,max_age)
from flask import Flask, make_response, request app = Flask(__name__) #設定cookie @app.route('/set_cookie') def set_cookie(): #呼叫make_response方法獲取響應體物件 response = make_response("set cookie") #設定cookie response.set_cookie("computer","lenovo") response.set_cookie("age","13",10) return response #獲取cookie @app.route('/get_cookie') def get_cookie(): #獲取cookie name = request.cookies.get("computer") age = request.cookies.get("age") #返回 return "name is %s, age is %s"%(name,age) if __name__ == '__main__': app.run(debug=True)
二、session
- 解釋: 伺服器和使用者來做狀態保持的,裡面儲存的是敏感資訊(比如身份證,登陸資訊),由伺服器設定,並存儲在伺服器
- 作用: 用來做使用者的登陸狀態保持
- session的設定和獲取
- 設定session: sessioin[key] = value
- 獲取session: value = session.get(key)
- 注意點:
- 1.session的儲存依賴於cookie
- 2.儲存在cookie中的sessionID需要加密,需要祕鑰(SECRET_KEY)
from flask import Flask, session app = Flask(__name__) #設定SECRET_KEY,此時就是隨意的字串 app.config["SECRET_KEY"] = "sdofinsidofnsfdas" #設定session @app.route('/set_session/<path:name>') def set_session(name): session["name"] = name return "set session!" #獲取session @app.route('/get_session') def get_session(): value = session.get("name") return "set session, name is %s"%value if __name__ == '__main__': app.run(debug=True)
三、上下文
- 解釋: 就是一個容器
- 請求上下文
- request: 封裝的是請求相關的資料
- session: 封裝的是和使用者相關的敏感資訊
- 應用上下文(在專案中具體應用)
- current_app: 是app的一個代理物件,可以通過他獲取app身上設定的各種屬性,主要用在模組化開發中
- g: 一個區域性的全域性變數,主要用在裝飾器中
from flask import Flask, current_app app = Flask(__name__) @app.route('/') def hello_world(): print(app.config.get("DEBUG")) print(current_app.config.get("DEBUG")) return "helloworld" if __name__ == '__main__': app.run(debug=True)
四、Flask_script
- 解釋: 屬於flaks的擴充套件
- 作用: 用來動態執行程式,配合flask_migrate做資料庫遷移
- 使用格式:
- 1.安裝
- pip install flask_script
- 2.匯入Manager類
- 3.建立物件manager,管理app
- 4.使用manager啟動程式
- 啟動命令: python xxx.py runserver -h(host是IP地址) -p(埠號) -d(除錯模式)
- 1.安裝
from flask import Flask
from flask_script import Manager
app = Flask(__name__)
app.config["DEBUG"] = True
#3.建立物件manager,管理app
manager = Manager(app)
@app.route('/')
def hello_world():
return "helloworld"
if __name__ == '__main__':
manager.run()
五、render_template
- 解釋: 屬於jinja2的模板函式
- 好處:
- 1.以後的檢視函式,只負責業務邏輯的處理,比如: 資料庫的增刪改查
- 2.以後資料的展示,全部都有jinja2的模板負責
- 使用格式:
- response = render_template('模板檔案',key=value)
模板檔案寫在自動生成的templates目錄下
如果是自己建的目錄需要這樣
from flask import Flask,render_template
app = Flask(__name__)
@app.route('/')
def hello_world():
response = render_template('template.html')
return response
if __name__ == '__main__':
app.run(debug=True)
template.html檔案
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.box{
width: 300px;
height: 300px;
background: red;
}
</style>
</head>
<body>
<div class="box">
</div>
</body>
</html>
六、模板語法,獲取變數
- 解釋: 在模板中獲取檢視函式的變數
- 格式:
- {{ 變數 }}
from flask import Flask,render_template
app = Flask(__name__)
@app.route('/')
def hello_world():
#1.定義各種型別的變數
number = 10
str = "老王"
tuple = (1,2,3,4,5)
list = [6,7,8,9,10]
dict = {
"name":"班長",
"age":29
}
#2.攜帶變數到模板中展示
return render_template("variable.html",number=number,str=str,tuple=tuple,list=list,dict=dict)
if __name__ == '__main__':
app.run(debug=True)
variable.html檔案
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>1.獲取各種變數的值</h1>
<h2>整數: {{number}}</h2>
<h2>字串: {{str}}</h2>
<h2>元祖: {{tuple}},分開獲取: {{tuple[0]}}, {{ tuple.1 }}</h2>
<h2>列表: {{list}},分開獲取: {{ list.0 }}, {{ list.1 }}</h2>
{# 如果字典使用方括號,獲取,需要寫成字串,如果不是字串,那麼則會被當成變數對待 #}
<h2>字典: {{dict}}, 分開獲取: {{ dict.name }}, {{ dict["age"] }}</h2>
</body>
</html>
七、模板語法,分支迴圈判斷
-
模板語法的種類
-
分支格式:
{% if 條件 %} 語句1 {% else%} 語句2 {% endif %}
-
迴圈語句格式:
{% for 變數 in 容器 %} {% endfor %}
-
註釋:
{# 這裡是註釋的內容 #}
-
from flask import Flask,render_template
app = Flask(__name__)
@app.route('/')
def hello_world():
#1.定義各種型別的變數
number = 10
str = "老王"
tuple = (1,2,3,4,5)
list = [6,7,8,9,10]
dict = {
"name":"班長",
"age":29
}
#2.攜帶變數到模板中展示
return render_template("programer.html",number=number,str=str,tuple=tuple,list=list,dict=dict)
if __name__ == '__main__':
app.run(debug=True)
對應的html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
h1{
color:red;
}
</style>
</head>
<body>
<h1>1.遍歷元祖中的偶數</h1>
{% for item in tuple %}
{% if item %2 == 0 %}
<h3>{{ item }}</h3>
{% endif %}
{% endfor %}
<h1>2.遍歷字典</h1>
{% for key in dict %}
{# dict.key那麼這個key會當成字典中的一個鍵, dict[key],那麼這個key當成一個變數 #}
<h3>{{ key }} = {{ dict[key] }}</h3>
{% endfor %}
</body>
</html>
八、系統字串過濾器
- 解釋: 過濾器,用來過濾想要的資料
- 格式: {{ 字串 | 字串過濾器 }}
- 常見的字串過濾器有:
- title: 將每個單詞的首字母都大寫
- lower: 將每個單詞都小寫
- upper: 將每個單詞都大寫
- reverse: 反轉
- ....
from flask import Flask,render_template
app = Flask(__name__)
@app.route('/')
def hello_world():
return render_template("stringfilter.html")
if __name__ == '__main__':
app.run(debug=True)
對應的html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{# 使用格式:{{ 字串 | 字串過濾器 }}#}
1.safe:禁用轉義,讓標籤生效
<p>{{ '<em>hello</em>' | safe }}</p>
2.capitalize:把變數值的首字母轉成大寫,其餘字母轉小寫
<p>{{ 'hello PYTHON' | capitalize }}</p>
3.lower:把值轉成小寫
<p>{{ 'HELLO PYthON' | lower }}</p>
4.upper:把值轉成大寫,中文沒有大小寫
<p>{{ 'hello python 你好' | upper }}</p>
5.title:把值中的每個單詞的首字母都轉成大寫
<p>{{ 'hello world python java' | title }}</p>
6.reverse:字串反轉
<p>{{ 'olleh' | reverse }}</p>
<p>{{ '我愛你' | reverse }}</p>
7.format:格式化輸出
<p>{{ '%s is %d' | format('age',17) }}</p>
8.striptags:渲染之前把值中所有的HTML標籤都刪掉
<p>{{ '<em>hello</em>' | striptags }}</p>
</body>
</html>
九、系統列表過濾器
- 解釋: 過濾器,用來過濾想要的資料
- 格式: {{ 列表 | 列表過濾器 }}
- 常見的列表過濾器有:
- first: 獲取列表第一個元素
- last: 最後一個元素
- sum: 列表和
- length: 列表長度
- ....
from flask import Flask,render_template
app = Flask(__name__)
@app.route('/')
def hello_world():
return render_template("list_fliter.html")
if __name__ == '__main__':
app.run(debug=True)
對應的html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{# * 使用格式:{{ 列表 | 列表過濾器 }}#}
1.first:取第一個元素
<p>{{ [1,2,3,4,5,6] | first }}</p>
2. last:取最後一個元素
<p>{{ [1,2,3,4,5,6] | last }}</p>
3. length:獲取列表長度
<p>{{ [1,2,3,4,5,6] | length }}</p>
4.sum:列表求和
<p>{{ [1,2,3] | sum }}</p>
5.sort:列表排序,預設升序
<p>{{ [6,2,3,1,5,4] | sort }}</p>
6.過濾器的鏈式呼叫
{# 過濾器的鏈式呼叫 #}
{{ "hello" | upper | reverse }}
</body>
</html>
十、自定義過濾器
-
解釋: 當系統提供的過濾器滿足不了需求的時候,需要自定義
-
自定義過濾器有兩種格式:
-
1.先定義好函式,再將函式新增到系統預設的過濾器列表中
- def 函式名: pass
- app.add_template_filter(函式名,'過濾器名字')
-
2.定義函式的時候,直接使用系統過濾器進行裝飾
@app.template_filter('過濾器名字') def 函式名(): pass
-
案例:
-
1.獲取列表偶數和
-
2.反轉列表
-
from flask import Flask,render_template
app = Flask(__name__)
# 1.先定義好函式,再將函式新增到系統預設的過濾器列表中
def get_oushu(list):
print(list)
sum = 0
for i in list:
if i %2 == 0:
sum += i
return sum
#引數1: 關聯的函式名稱, 引數2: 在模板中使用的過濾器名字
app.add_template_filter(get_oushu,"oushu")
# 2.定義函式的時候,直接使用系統過濾器進行裝飾
@app.template_filter("reverse")
def listreverse(list):
list.reverse()
return list
@app.route('/')
def hello_world():
return render_template("custom_filter.html")
if __name__ == '__main__':
app.run(debug=True)
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h2>原列表: {{ [1,2,3,4,5,6] }}</h2>
<h2>偶數列表: {{ [1,2,3,4,5,6] | oushu }}</h2>
<h2>反轉列表: {{ [1,2,3,4,5,6] | reverse }}</h2>
<h2>降序列表: {{ [1,2,3,4,5,6,10,9,7] | sort | reverse }}</h2>
</body>
</html>
十一、程式碼複用之巨集
-
解釋: 相當於python中的函式,定義好一段功能,在需要的時候進行呼叫即可
-
定義格式:
{% macro 巨集名(引數) %} {% endmacro %}
-
使用格式:
// 使用當前檔案定義好的巨集 {{ 巨集名(引數) }} //使用其他檔案定義好的巨集 {% import '檔案' as 別名%} {{ 別名.巨集名(引數) }}
from flask import Flask,render_template
app = Flask(__name__)
@app.route('/')
def hello_world():
return render_template("file07macro.html")
if __name__ == '__main__':
app.run(debug=True)
使用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{# 定義巨集 #}
{% macro my_macro(name,password) %}
使用者名稱: <input type="text" value="{{ name }}"><br>
密碼: <input type="password" value="{{ password }}"><br>
{% endmacro %}
{# 呼叫當前檔案巨集 #}
{{ my_macro("zhangsan","111111") }}
{# 使用其他檔案的巨集 #}
{% import 'othermacro.html' as other %}
{{ other.my_input() }}
{{ other.my_div() }}
</body>
</html>
othermacro.html
{% macro my_macro(name,password) %}
使用者名稱: <input type="text" value="{{ name }}"><br>
密碼: <input type="password" value="{{ password }}"><br>
{% endmacro %}
{% macro my_input() %}
<h1>這是一個其他檔案的巨集</h1>
{% endmacro %}
{% macro my_div() %}
<div style="color: red;">我是一個孤獨的div</div>
{% endmacro %}
十二、程式碼複用之繼承
-
解釋: 一個子模板繼承自父模板
-
作用: 共性抽取,程式碼複用
-
父模板
- 1.所有子類都具有的相同的內容的, 在父模板中直接寫死
- 2.每個子類的模板中不一樣的內容,使用block模板定義好
-
子模板
- 1.根據子類自己的需求,去重寫父類中的block對應的內容
- 2.如果重寫之後,還想保留父類的內容,那麼使用{{super()}}
- 3.繼承格式: {% extends '父檔名'%}, 寫在頁面的頂部
-
注意點:
-
定義block的格式
{% block 名稱 %} {% endblock %}
-
from flask import Flask,render_template
app = Flask(__name__)
@app.route('/')
def hello_world():
# return render_template("file09zi.html")
return render_template("file10zi.html")
if __name__ == '__main__':
app.run(debug=True)
file11fu.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{# 頭部部分 #}
{% block titleBlock %}
<h1>靜夜思</h1>
{% endblock %}
{# 正文部分 #}
{% block contentBlock %}
{% endblock %}
{# 底部部分 #}
<div>
<a href="#">點我有驚喜</a>
</div>
</body>
</html>
file09zi.html
{% extends 'file11fu.html' %}
{# 重寫正文部分 #}
{% block contentBlock %}
<p>
床前一鍋湯,<br>
撒了一褲襠, <br>
抬頭拿抹布, <br>
低頭擦褲襠 <br>
</p>
{% endblock %}
{#<!DOCTYPE html>#}
{#<html lang="en">#}
{#<head>#}
{# <meta charset="UTF-8">#}
{# <title>Title</title>#}
{#</head>#}
{#<body>#}
{##}
{# <h1>靜夜思</h1>#}
{##}
{# <p>#}
{# 床前一鍋湯,<br>#}
{# 撒了一褲襠, <br>#}
{# 抬頭拿抹布, <br>#}
{# 低頭擦褲襠 <br>#}
{# </p>#}
{##}
{# <div>#}
{# <a href="#">點我有驚喜</a>#}
{# </div>#}
{##}
{##}
{#</body>#}
{#</html>#}
file10zi.html
{% extends 'file11fu.html' %}
{# 重寫父類titleBlock內容 #}
{% block titleBlock %}
{{ super() }}
<h1>新靜夜思</h1>
{% endblock %}
{# 重寫父類中的contentBlock內容 #}
{% block contentBlock %}
<p>
床前明月光,<br>
疑似地上霜, <br>
舉頭望明月, <br>
低頭思故鄉 <br>
</p>
{% endblock %}
{#<!DOCTYPE html>#}
{#<html lang="en">#}
{#<head>#}
{# <meta charset="UTF-8">#}
{# <title>Title</title>#}
{#</head>#}
{#<body>#}
{##}
{# <h1>靜夜思</h1>#}
{##}
{# <p>#}
{# 床前明月光,<br>#}
{# 疑似地上霜, <br>#}
{# 舉頭望明月, <br>#}
{# 低頭思故鄉 <br>#}
{# </p>#}
{##}
{# <div>#}
{# <a href="#">點我有驚喜</a>#}
{# </div>#}
{##}
{##}
{#</body>#}
{#</html>#}
十三、程式碼複用之包含
-
解釋: 在一個檔案中完全擁有另外一個檔案,不夠靈活,沒法擴充套件
-
格式:
方式一: {% include '檔案' %} 方式二: {% include '檔案' ignore missing %}
-
注意點: ignore missing 如果包含的檔案不存在,也不會報錯
十四、模板使用練習
- 題目: 給出5條資料,顯示前四條
"""
給定如下5條資料,只顯示4行資料,背景顏色依次為:黃,綠,紅,紫
my_list = [
{
"id": 1,
"value": "我愛工作"
},
{
"id": 2,
"value": "工作使人快樂"
},
{
"id": 3,
"value": "沉迷於工作無法自拔"
},
{
"id": 4,
"value": "日漸消瘦"
},
{
"id": 5,
"value": "以夢為馬,越騎越傻"
}
]
"""
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def hello_world():
#1.定義5條資料
my_list = [
{
"id": 1,
"value": "我愛工作"
},
{
"id": 2,
"value": "工作使人快樂"
},
{
"id": 3,
"value": "沉迷於工作無法自拔"
},
{
"id": 4,
"value": "日漸消瘦"
},
{
"id": 5,
"value": "以夢為馬,越騎越傻"
}
]
#2.在模板中顯示4條
return render_template("practice.html",list=my_list)
if __name__ == '__main__':
app.run(debug=True)
practice.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<ul>
{# 如果dict.id 不等於5才遍歷 #}
{% for dict in list if dict.id !=5 %}
{# 方式一 #}
{# {% if dict.id == 1 %}#}
{# <li style="background: yellow;"> {{ dict.value }} </li>#}
{# {% elif dict.id == 2 %}#}
{# <li style="background: green;"> {{ dict.value }} </li>#}
{# {% elif dict.id == 3 %}#}
{# <li style="background: red;"> {{ dict.value }} </li>#}
{# {% else %}#}
{# <li style="background: purple;"> {{ dict.value }} </li>#}
{# {% endif %}#}
{# 遍歷的時候可以獲取到從0開始的索引 #}
{# <h3>{{ loop.index0 }}</h3>#}
{# 遍歷的時候可以獲取到從1開始的索引 #}
{# <h3>{{ loop.index }}</h3>#}
{# 方式二 #}
{% if loop.index == 1 %}
<li style="background: yellow;"> {{ dict.value }} </li>
{% elif loop.index == 2 %}
<li style="background: green;"> {{ dict.value }} </li>
{% elif loop.index == 3 %}
<li style="background: red;"> {{ dict.value }} </li>
{% else %}
<li style="background: purple;"> {{ dict.value }} </li>
{% endif %}
{% endfor %}
</ul>
</body>
</html>
十五、模板特有變數
- 解釋: 不需要通過python程式傳遞就可以直接使用的變數
- 常見的特有變數如下:
- config: 就是flask中的app.config, 表示應用程式中的所有配置資訊
- request: 表示請求上下文物件,封裝的是請求相關的資料
- g: 區域性的全域性變數(瞭解)
- url_for(): 反解析,通過函式的名字,解析到檢視函式的路徑
- get_flashed_messsages(): 用來消耗flash方法中儲存的訊息.
- 場景: 登陸出錯,可以顯示
- 注意點:
- 1.使用flash儲存訊息的時候需要設定SECRET_KEY
- 2.因為flash內部的訊息儲存,依賴於了session
from flask import Flask,render_template
app = Flask(__name__)
app.config["SECRET_KEY"] ="hahaha"
@app.route('/')
def hello_world():
return render_template("special_variable.html")
@app.route('/test/<int:age>')
def test(age):
return "test..."
if __name__ == '__main__':
app.run(debug=True)
special_variable.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h2>config變數: {{ config }}</h2>
<h2>request: {{ request.method }}</h2>
<h2>request: {{ request.url }}</h2>
<h2>url_for(): {{ url_for("hello_world") }}</h2>
<h2>url_for(): {{ url_for("test",age=100) }}</h2>
</body>
</html>
get_flashed_messsages()的使用
from flask import Flask,render_template,flash
app = Flask(__name__)
app.config["SECRET_KEY"] = "onjgtex"
@app.route('/')
def hello_world():
return render_template("flash.html")
@app.route('/test')
def test():
#儲存訊息
flash("登陸成功")
return "test"
if __name__ == '__main__':
app.run(debug=True)
flash.html
用來消耗flash方法中儲存的訊息
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{{ get_flashed_messages() }}
</body>
</html>
十六、csrf攻擊流程
- 解釋: 跨站點請求偽造
- 掌握: 需要理解講義中的攻擊流程圖
- 程式碼演示: webA, webB
十七、csrf攻擊手動解決
- 在cookie增加一個csrf_token
- 在表單中增加一個csrf_token
- 校驗: 取出cookie和表單中的csrf_token比較如果二者一致那麼是正常請求
- 具體過程,看keynote圖解
十八、CSRFProtect解決csrf
- 使用流程:
- 1.安裝擴充套件包
- pip install flask-wtf
- 2.匯入包
- from flask_wtf.csrf import CSRFProtect
- 3.設定SECRET_KEY,便於csrf_token加密
- 4.建立CSRFProtect物件,保護app物件
- 5.需要在表單中設定csrf_token隱藏欄位即可
- 例子: 註冊案例
- 注意點: CSRFProtect一旦保護了app之後, 會對'POST', 'PUT', 'PATCH', 'DELETE'做校驗.
- 1.安裝擴充套件包
from flask import Flask, render_template, request
from flask_wtf.csrf import CSRFProtect
app = Flask(__name__)
# 1. 先設定金鑰
app.config["SECRET_KEY"] = "weorinsaiudfhnb"
# 2. 保護app
CSRFProtect(app)
@app.route('/', methods=["GET", "POST"])
def index():
if request.method == "POST":
# 獲取到引數
username = request.form.get("username")
password = request.form.get("password")
repassword = request.form.get("repassword")
# 校驗引數
if not all([username, password, repassword]):
return "引數填寫不全"
# 判斷兩次的密碼是否一致
if password != repassword:
return "兩次密碼輸入不一致,請重新輸入"
return "註冊成功"
else:
return render_template("register.html")
if __name__ == '__main__':
app.run()
對應的register.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/" method="post">
{# 3. 只要使用了CSRFProtect保護app,就可以直接使用csrf_token()作為value值 #}
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
使用者名稱:<input type="text" name="username"><br>
密碼:<input type="password" name="password"><br>
確認密碼:<input type="password" name="repassword"><br>
<input type="submit" value="註冊">
</form>
</body>
</html>