文章目錄
flask框架總結
特點:短小精悍,支持三方組件,穩定性相對其他框架較差。
web服務端,基於socket製作
原理
wsgi:應用程序網關接口
django使用的是uwsgi
flask使用的是werkzeug(wsgi封裝)
請求上下文原理
在flask中reqeust和session都爲公共變量,直接通過flask導入,而不是通過參數傳入視圖函數
實現原理是:
wsgi處理-》打包成ctx=RequestContext(包含reqeust,session)->ctx.push(將當前請求信息存入棧中)-》視圖函數處理-》執行reqeust相關方法時,從棧中獲取數據
{__storage__:{線程號:{"stack":[ctx]}},__ident_func__:get_ident}
get_ident爲獲取線程號的方法名
flask握手原理
websocket通信原理
後端
獲取請求體中字符串Sec-WebSocket-Key,拿到key
用magic_string字符串與其拼接,使用sha1加密,再用base64加密
拼接響應頭,添加Sec-WebSocket-Accept字段,發送給瀏覽器
前端瀏覽器
鏈接服務器,發送請求頭,含Sec-WebSocket-Key字段
獲取響應頭,解密,校驗握手是否成功
flask發送數據加密,解密原理
解密
瀏覽器send發送數據過來爲bytes類型
- 第1位,固定\x81
- 第2位, 首先與127進行與運算 有0得0 data_length結果有3種情況
情況一: <= 125 當前data_length就爲數據長度 125(3-6爲mask_key)
情況二:==126 數據長度兩位,3-4字節爲數據長度 65535(5-8mask_key)
情況三:==127 數據長度爲八位,3-10字節爲數據長度 2**64(11-14mask_key) - 往後四位,爲mask—key,爲密鑰,可以解密後面的字符串
bytes = decode[i] ^ mask[i%4]
每位用或運算和mask—key的四個數
加密
- 解碼msg爲bytes類型
- 第一位固定爲\x81
- 計算程度,根據長度不同,打包的數據大小不同
struct打包
情況一: < 126struct.pack("B",length)
情況二: == 126struct.pack("!BH",126,length)
情況三: > 126struct.pack("!BQ",127,length)
- 拼接發送
快速啓動flask服務
from flask import Flask
app = Flask(__name__) #在該模塊中Flask標識,可以傳入任意字符串
@app.route('/') #裝飾器第一個參數爲路由
def index():
return "hello world" # 直接返回字符串到頁面上
app.run() # 啓動flask
app.run()接受參數如下
run(self, host=None, port=None, debug=None, load_dotenv=True, **options):
例如:
app.run(host="127.0.0.1",port=9527,debug=True)
debug爲true時,每次修改代碼後,自動重啓服務
app.route()裝飾器接受參數如下
@app.route('/hi2',endpoint="hi2",redirect_to="/",methods=("GET","POST"),defaults={"age":22})
def hi2(age):
return redirect('/')
endpoint:函數標識,默認爲函數名,在反向解析時使用url_for(‘hi2’)可以解析出url。 當函數重名時,只要endpoint不重名即可
redirect_to:不通過視圖函數,直接重定向(永久重定向)
methods:允許請求方法,默認只允許GET,可以傳入一個列表或元組
defaults:默認參數,默認傳入視圖函數的參數,視圖函數必須要有參數來接受
strict_slashes:嚴格匹配,默認值爲False,值爲True時,地址末尾多一個斜槓也不允許訪問
動態路由參數
可以使用<>方式添加變量名,同時視圖函數也要接受參數,來匹配路由
<a> <int:b> <string:c>
默認參數類型是字符串
@app.route('/hi/<normal>/<int:age>')
def hi(normal,age):
print(normal,age)
return redirect('/')
處理請求方法
處理請求有CBV和FBV兩種方式
FBV:在視圖中,通過函數類處理請求
CBV:在視圖中,通過類來處理請求
FBV 方法示例
通常我們使用函數加裝飾器方法組成視圖函數
@app.route('/')
def index():
return "hello world"
等價於
def index2():
return "hello world1"
app.add_url_rule("/index2",view_func=index2)
view_func爲視圖函數的函數名
CBV方法示例
from flask import views
def war(func):
def inner(*args,**argv):
print("inner")
return func(*args,**argv)
return inner
class Index3(views.MethodView):
methods = ["GET","POST"]
decorators = [war]
def get(self):
return "nice get"
def post(self):
return "nice post"
app.add_url_rule(rule="/test",view_func=Index3.as_view(name="index33"))
類需要繼承views.MethodView,類中添加相應請求方法的處理函數(get方法請求,就添加名爲get的函數)
methods:默認爲只允許get方法訪問
decorators: 將類中每個函數添加裝飾器,每次執行函數時,自動依次執行裝飾器
as_view:將類轉換爲相應視圖函數,name爲函數標識
flask響應三劍客
from flask import Flask,render_template,redirect,jsonify,send_file
@app.route('/')
def index():
return "hello world"
@app.route("/login")
def login():
return render_template('login.html')
@app.route('/hi')
def hi():
return redirect('/')
@app.route("/hello")
def hello():
return jsonify({"name":"xiaoming","age":16})
@app.route("/web")
def web():
return send_file("./small.png")
直接返回字符串,類似於django的HttpResponse
render_template返回模板,類似於django的render
redirect重定向(默認302臨時重定向),和django一樣
jsonify返回json字符串,content-Type爲Content-Type: application/json
send_file返回一個本地文件,根據文件不同content-Type不同
reqeust
reqeust爲一個全局變量,獲取請求信息,所有請求信息經過wsgi處理後轉換爲鍵值對形式存入字典中
from flask import request
@app.route('/')
def index():
print(request.method) #返回當前請求方法
print(request.args) #get攜帶的參數鍵值對(字典),get取值
print(request.form) #表單提交<form>的結果(字典),get取值
print(request.json) #數據格式application/json bytes類型
print(request.data) #request定義的格式不存在的 application/xiaowangba bytes類型的數組
print(request.values) #同時獲得url攜帶參數和post請求獲取的參數,get取值如果get和post請求參數重名時,取get請求參數的值因爲先序列化form,後序列化args,args同名參數會將其覆蓋
return "hello world"
request還有url,path等方法
模板語法jinja2
在django和flask中都使用了jinja2語法
變量語法 {{ msg }}
tag標籤語法 邏輯代碼 {% if %}
for語法
遍歷
{% for stu in stu_list %}
{% endfor %}
獲取字典值時,可以使用下標,[],get方法
<td>{{ student.name }}</td>
<td>{{ student["name"] }}</td>
<td>{{ student.get("name") }}</td>
獲取列表值時,可以使用下標方法或傳入索引
<td>{{ student[0] }}</td>
<td>{{ student.0 }}</td>
if語法
條件判斷
{% if session %}
{% elif session1 %}
{% else %}
{% endif %}
示例
{% if student.3 == 'female' %}
<input class="form-check-input" type="radio" name="sex" id="female" value="female" checked>
{% else %}
<input class="form-check-input" type="radio" name="sex" id="female" value="female">
{% endif %}
safe過濾器
將變量中字符串渲染成標籤
{{ msg|safe }}
默認情況,字符串不能直接被渲染成字符串,必須使用safe
過濾器
Markup
類似於safe,只不是在後端執行
from flask import Markup
@app.route('/1')
def index1():
text_tag = "<p>我是p標籤</p>"
text_tag = Markup(text_tag)
return render_template("index.html",msg=text_tag)
將字符串轉換爲標籤,在頁面上渲染
傳入函數名
後端也可以直接向前端傳入函數名,前進接受後直接使用
python
def add(a,b):
return a+b
@app.route('/2')
def index2():
return render_template("index.html",add=add)
html
{{ add(1,2) }}
自定義標籤
自定義全局函數
python
@app.template_global()
def add_tag(*args):
return sum(*args)
不需要通過參數傳入模板,直接在模板中調用
html
{{ add_tag([1,2,3]) }}
自定義過濾器
自定義全局過濾器
python
@app.template_filter()
def jiou(num):
return "奇數" if num % 2 else "偶數"
html
{{ 5|jiou }}
extends標籤
繼承父模板框架,必須卸載最上方
block:在index.html中爲佔位符,在index2.html中爲實際內容
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{% block container %}
<p>默認顯示內容,沒有block時顯示</p>
{% endblock %}
</body>
</html>
index2.html
{% extends "index.html" %}
{% block container %}
<p>新內容</p>
{% endblock %}1
include標籤
include:導入代碼塊,將代碼塊導入到網頁中
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{% include "login.html" %}
</body>
</html>
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登錄</title>
</head>
<body>
登錄
</body>
</html>
include和extend區別
include:用於多個html頁面,有相同代碼部分,這部分用include導入,比如導入小廣告
extends:用戶同一主題的頁面,用相同主題,只修改block部分,其他部分不變。extends必須寫在頁面開頭,配合block使用。模板繼承
宏指令
創建標籤,宏指令
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登錄</title>
</head>
<body>
登錄
{% macro create_tag(name) %}
<p>{{ name }}</p>
{% endmacro %}
{{ create_tag("xiaoming") }}
{{ create_tag("wanghua") }}
</body>
</html>
相當於html中的函數,傳入參數,執行參數
session
session和cookie用戶信息的緩存,cookie一般存放在用戶端,session一般存放在服務端
但是flask原生session是將用戶信息存放在cookie中,也就是用戶端
from flask import session
app = Flask(__name__)
app.secret_key = "this_is_any_string"
@app.route('/3')
def index3():
session["name"] = "xiaoming" #添加一個session鍵值對
print(session["name"]) #獲取session值
return render_template("test.html")
注意:首先導入session,其次必須要secret_key
session存放在cookie中,鍵session,值(secret_key經過md5序列化+時間戳+session字典中的鍵值)
flask配置
app配置
方法一:
使用字典方式設置
from flask import Flask
app = Flask(__name__)
app.config["DEBUG"]=True
方法二:
使用對象方式
obj爲類
class obj():
DEBUG:True
SECERT_KEY="1234567890"
app.config.from_object(obj)
在對象中設置值
初始化配置
flask示例初始化配置
app = Flask(__name__)
'''
def __init__(
self,
import_name, #該參數用來標識實例的(用來區分是否是一個實例化對象,request等)
static_url_path=None, #訪問靜態文件的url 默認等於static_folder
static_folder="static", #靜態文件夾
static_host=None, #遠程訪問靜態文件(靜態文件夾不在本地)必須和host_matching一起用
host_matching=False,
subdomain_matching=False,
template_folder="templates", #指定模板文件夾
instance_path=None,
instance_relative_config=False,
root_path=None,
):
'''
flask藍圖
flask藍圖相當於不能運行的flask實例,用來做插件用
student_add.py
from flask import Blueprint
stu_add = Blueprint("stu_add",__name__)
@stu_add.route("/student_add",methods=("GET",'POST'))
def student_add():
return render_template("student_add.html")
參數一位藍圖實例名,用來區分藍圖與藍圖
參數二藍圖空間標識
注意:藍圖默認static和template和app默認存儲位置相同
註冊藍圖
main.py
from student_add import stu_add
app.register_blueprint(stu_add.stu_add)
即可使用
藍圖中的視圖函數名與app視圖函數名相同時不會出錯,但url_for反向解析時會報錯
flask中間件
flask使用兩種裝飾器類似於django中的中間件
@app.before_request
def is_login():
white_list = ['/login',]
if request.path in white_list:
return None
if session.get("is_login") and session["is_login"] + 3000*60 > time.time():
return None
else:
return redirect('/login')
@app.after_request
def go(res):
print("after")
return res
- before_request在每次進入任何視圖函數前使用,after_request在每次出視圖函數前使用 2. after_request必須傳入一個參數response,返回這個參數
- before_request執行順序,代碼順序before1->before2,在請求進入視圖函數之前作出處理
- after_request執行順序,從後向先執行 after2->after1 代碼在前面的,執行順序靠後
- 正常執行順序:before1->before2->after2->after1
- 當before2出現異常時,before1->after2->after1
自定義錯誤errorhandler
可以自定義404錯誤
@app.errorhandler(404)
def errors(*args):
print(args)
return "沒有找到當前頁面"
也可以自定義錯誤頁面
flask中flash閃現
flash存一次,取一次後就銷燬,不佔空間。
通常用來上一個位置使用
from flask import flash,get_flashed_messages
@app.route("/home")
def home():
res = get_flashed_messages()
print(res)
flash("home")
return render_template("home.html",loc = res)
@app.route("/music")
def music():
res = get_flashed_messages()
print(res)
flash("music")
return render_template("music.html",loc = res)