一、flask介紹
??Flask和Django一樣,也是一個基于MVC設(shè)計模式的Web框架
??Flask流行的主要原因:
1. 有非常齊全的官方文檔,上手非常方便
2. 有非常好的拓展機(jī)制和第三方的拓展環(huán)境,工作中常見的軟件都有對應(yīng)的拓展,自己動手實現(xiàn)拓展也很容易
3. 微型框架的形式給了開發(fā)者更大的選擇空間
二、安裝flask
pip install flask
三、安裝管理庫
pip install flask-script
四、導(dǎo)入管理庫中的Manager,用Manager管理項目
將flask對象交給Manager管理如下
manage = Manager(app)
manage.run()
??用manage啟動項目
python hello.py runserver -h 0.0.0.0 -p 8080 -d
??參數(shù)說明:
-h 指定主機(jī)地址
-p 指定端口號
-d 指定用debug方式啟動
路由接收參數(shù)
@app.route('/stu/<id>/')
def stu(id):
# 接收的參數(shù)是字符串
return f'stu id: {id}'
@app.route('/grade/<int:id>/')
def grade(id):
# 指定接收的參數(shù)是int類型
return f'grade id: {id}'
可以指定許多接收參數(shù)類型但常用的就是int和string
@app.route('/path/<path:url>/')
def get_path(url):
# 接收url中path后面的全部路徑
return f'url: {url}'
@app.route('/get_uuid/')
def get_uuid():
import uuid
# 獲取一個uuid,uuid是一個唯一的字符串
return str(uuid.uuid4())
@app.route('/uuid/<uuid:u>/')
def my_uuid(u):
# 指定接收的參數(shù)為uuid類型的值
return f'uuid: {u}'
??python框架主要
Django
Flask
Tronado
Sanic 性能最優(yōu)但是一般不再線上使用
Twisted 主要是針對底層協(xié)議
??將flask項目提煉成mvc的形式
??安裝藍(lán)圖(就是模塊化管理路由),相當(dāng)于Django中的urls.py
pip install flask-blueprint
??使用:
from flask import Blueprint
# 模塊化管理路由 Blueprint
# 第一步:生成藍(lán)圖對象
blueprint = Blueprint('first', __name__)
# 第二步:在管理文件中注冊一個藍(lán)圖,也就是將應(yīng)用綁定在應(yīng)用上
app.register_blueprint(blueprint=blueprint, url_prefix='/app')
# url_prefix: url訪問前綴127.0.0.1/app/
前綴相當(dāng)于Django中的namespace
??路由跳轉(zhuǎn)
@blueprint.route('/redirect/')
def my_redirect():
# 跳轉(zhuǎn)到無參方法
# redirect: 跳轉(zhuǎn)
# url_for:反向解析出地址
# 'first.hello_world': 藍(lán)圖第一個 參數(shù).跳轉(zhuǎn)到的函數(shù)名
return redirect(url_for('first.hello_world'))
@blueprint.route('/redirect_id/')
def stu_redirect():
# 有參數(shù)的跳轉(zhuǎn)
return redirect(url_for('first.stu', id=3))
五、請求與相應(yīng)
??1. 請求:
@blueprint.route('/req/', methods=['GET', 'POST', 'PUT', 'PATCH', 'DELETE'])
def req():
# methods = ['GET', 'POST']指定能接收的請求類型
if request.method == 'GET':
# 獲取get請求中的參數(shù)
# request.agrs.get(key)
# 獲取get請求中多個相同key的參數(shù)的值,返回列表
# request.args.getlist(key)
return 'hello get'
if request.method == 'POST':
# 獲取post請求中傳遞的參數(shù)
# request.form.get(key)
# 獲取post請求中相同key的參數(shù),返回列表
# request.form.getlist(key)
??2. 響應(yīng):
從flask中導(dǎo)入響應(yīng)模塊
創(chuàng)建響應(yīng)對象
res = make_response(響應(yīng)內(nèi)容,狀態(tài)碼)
設(shè)置cookie
res.set_cookie(key, value, max_age, expires)
key: 鍵
value: 值
max_age: 過期時間,秒為單位
expires: 過期時間,datetime為單位
刪除cookie
方式一: res.delete_cookie(key)
方式二: res.set_cookie(key, value, max_age=0) 過期時間為0相當(dāng)于刪除
六、裝飾器驗證登錄狀態(tài)
??裝飾器的三個特點:
1. 外層函數(shù)內(nèi)嵌內(nèi)層函數(shù)
2. 內(nèi)層函數(shù)調(diào)用外層函數(shù)的參數(shù)
3. 外層函數(shù)返回內(nèi)層函數(shù)
??自定義一個登錄簡單的登錄驗證裝飾器
from flask import session, redirect, url_for
from functools import wraps
def login_status(func):
# 使用functools裝飾該內(nèi)嵌函數(shù),用于維持被裝飾函數(shù)的部分屬性,如__name__/__doc__/__module__
@wraps(func)
def check_login(*args, **kwargs):
# 獲取登錄后在session中設(shè)置的user_id,由于標(biāo)識用戶登錄狀態(tài)
user_id = session.get('user_id')
if user_id:
# 有user_id說明登錄,則繼續(xù)執(zhí)行被裝飾函數(shù)
return func(*args, **kwargs)
else:
# 如果沒有user_id說明沒有登錄,則跳轉(zhuǎn)道登錄界面
return redirect(url_for('first.hello_world'))
return check_login
??functools庫函數(shù)簡介
??1. update_wrapper
??更新一個包裹(wrapper)函數(shù),使其看起來更像被包裹(wrapped)的函數(shù)。
??可選的參數(shù)指定了被包裹函數(shù)的哪些屬性直接賦值給包裹函數(shù)的對應(yīng)屬性,同時包裹函數(shù)的哪些屬性要更新而不是直接接受被包裹函數(shù)的對應(yīng)屬性,參數(shù)assigned的默認(rèn)值對應(yīng)于模塊級常量WRAPPER_ASSIGNMENTS(默認(rèn)地將被包裹函數(shù)的 name, module,和 doc 屬性賦值給包裹函數(shù)),參數(shù)updated的默認(rèn)值對應(yīng)于模塊級常量WRAPPER_UPDATES(默認(rèn)更新wrapper函數(shù)的 dict 屬性)。
??這個函數(shù)的主要用途是在一個裝飾器中,原函數(shù)會被裝飾(包裹),裝飾器函數(shù)會返回一個wrapper函數(shù),如果裝飾器返回的這個wrapper函數(shù)沒有被更新,那么它的一些元數(shù)據(jù)更多的是反映wrapper函數(shù)定義的特征,無法反映wrapped函數(shù)的特性。
??2. wraps
??這個函數(shù)可用作一個裝飾器,簡化調(diào)用update_wrapper的過程,調(diào)用這個函數(shù)等價于調(diào)用partial(update_wrapper, wrapped = wrapped, assigned = assigned,updated = updated)。
from functools import wraps
def my_decorator(f):
@wraps(f)
def wrapper(*args,**kwds):
print "Calling decorated function"
return f(*args,**kwds)
return wrapper
@my_decorator
def example():
"""DocString"""
print "Called example function"
example()
print example.__name__
print example.__doc__
??控制臺輸出,
Calling decorated function
Called example function
example
DocString
??可以看到,最終調(diào)用函數(shù)example時,是經(jīng)過 @my_decorator裝飾的,裝飾器的作用是接受一個被包裹的函數(shù)作為參數(shù),對其進(jìn)行加工,返回一個包裹函數(shù),代碼使用 @functools.wraps裝飾將要返回的包裹函數(shù)wrapper,使得它的 name, module,和 doc 屬性與被裝飾函數(shù)example完全相同,這樣雖然最終調(diào)用的是經(jīng)過裝飾的example函數(shù),但是某些屬性還是得到維護(hù)。
如果在 @my_decorator的定義中不使用 @function.wraps裝飾包裹函數(shù),那么最終example.name 將會變成'wrapper',而example.doc 也會丟失。
將 @wraps(f)注釋掉,然后運行程序,控制臺輸出,
Calling decorated function
Called example function
wrapper
None
??所以在上面我們自定義的登錄狀態(tài)驗證裝飾器就需要用到functools庫中的wraps來裝飾內(nèi)嵌函數(shù),維持被裝飾的函數(shù)的_name_、_module_、_doc_屬性,如果不用wraps裝飾當(dāng)我們在視圖函數(shù)中進(jìn)行反向解析被裝飾函數(shù)時,會報如下錯誤:

如:
@blueprint.route('/')
@login_status
def hello_world():
return 'hello'
@blueprint.route('/login/', methods=['GET', 'POST'])
def login():
if request.method == 'GET':
return render_template('login.html')
if request.method == 'POST':
# 模擬登錄
username = request.form.get('username')
password = request.form.get('password')
if username == 'root' and password == '123123':
# 設(shè)置session值
session['user_id'] = 1
return redirect(url_for('first.hello_world')) # 如果沒有用@wraps裝飾裝飾器的內(nèi)嵌函數(shù)則者句話在做反向解析時就會拋出上面提到的異常