flask框架總結

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. 第1位,固定\x81
  2. 第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)
  3. 往後四位,爲mask—key,爲密鑰,可以解密後面的字符串
    bytes = decode[i] ^ mask[i%4]
    每位用或運算和mask—key的四個數

加密

  1. 解碼msg爲bytes類型
  2. 第一位固定爲\x81
  3. 計算程度,根據長度不同,打包的數據大小不同
    struct打包
    情況一: < 126 struct.pack("B",length)
    情況二: == 126 struct.pack("!BH",126,length)
    情況三: > 126 struct.pack("!BQ",127,length)
  4. 拼接發送

快速啓動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
  1. before_request在每次進入任何視圖函數前使用,after_request在每次出視圖函數前使用 2. after_request必須傳入一個參數response,返回這個參數
  2. before_request執行順序,代碼順序before1->before2,在請求進入視圖函數之前作出處理
  3. after_request執行順序,從後向先執行 after2->after1 代碼在前面的,執行順序靠後
  4. 正常執行順序:before1->before2->after2->after1
  5. 當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)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章