# 最全的零基礎Flask教程 ## 1 Flask介紹 ### 1.1 為什麼要使用Flask Django和Flask是Python使用最多的兩個框架 用 Python 語言基於 Werkzeug 工具箱編寫的輕量級Web開發框架。
Flask 本身相當於一個內核,其他幾乎所有的功能都要用到擴展(郵件擴展Flask-Mail,用戶認證Flask-Login,資料庫Flask-SQLAlchemy),都需要用第三方的擴展來實現。比如可以用 Flask 擴展加入ORM、窗體驗證工具,文件上傳、身份驗證等。Flask 沒有預設使用的資料庫,你可以選擇 MySQL,也可以用 NoSQL。
其 WSGI 工具箱採用 Werkzeug(路由模塊),模板引擎則使用 Jinja2。這兩個也是 Flask 框架的核心。
1.3 Flask與Django框架對比
1.3.1 框架輕重
重量級的框架:為方便業務程式的開發,提供了豐富的工具、組件,如Django
輕量級的框架:只提供Web框架的核心功能,自由、靈活、高度定製,如Flask、Tornado
1.3.2 與Django對比
django提供了:
- django-admin快速創建項目工程目錄
- manage.py 管理項目工程
- orm模型(資料庫抽象層)
- admin後臺管理站點
- 緩存機制
- 文件存儲系統
- 用戶認證系統
- 而這些,flask都沒有,都需要擴展包來提供
1.4 Flask常用擴展包
- Flask-SQLalchemy:操作資料庫;
- Flask-script:插入腳本;
- Flask-migrate:管理遷移資料庫;
- Flask-Session:Session存儲方式指定;
- Flask-WTF:表單;
- Flask-Mail:郵件;
- Flask-Bable:提供國際化和本地化支持,翻譯;
- Flask-Login:認證用戶狀態;
- Flask-OpenID:認證;
- Flask-RESTful:開發REST API的工具;
- Flask-Bootstrap:集成前端Twitter Bootstrap框架;
- Flask-Moment:本地化日期和時間;
- Flask-Admin:簡單而可擴展的管理介面的框架
1.5 Flask文檔
2 工程搭建
2.1 環境安裝
2.1.1 Anaconda常用虛擬環境命令
# 虛擬環境
conda create -n 虛擬環境名稱 python=python版本號 # 創建虛擬環境
conda remove -n 虛擬環境名稱 --all # 刪除虛擬環境
conda activate 虛擬環境名稱 # 激活虛擬環境
conda env list 或 conda info -e # 查看全部虛擬環境
deactivate 虛擬環境名稱 # 退出虛擬環境
2.1.2. 創建虛擬環境
Flask 再2.3.0
版本上已經放棄對Python3.7
的支持,當前支持的Python把版本區間為3.7~3.12
,因此這裡將Python的版本定為3.8
conda create -n FlaskWeb python=3.8
2.1.3. 安裝Flask
使用flask 2.3.0版本
pip install flask==2.3.0
2.2 HelloWorld程式
2.2.1 Flask編寫
2.2.2 Flaks手動運行
1 Pycharm
運行
2 命令行運行
3 訪問測試
2.3 參數說明
2.3.1 Flask對象初始化參數
Flask 程式實例在創建的時候,需要預設傳入當前 Flask 程式所指定的包(模塊),下麵說明一些常用的Flask參數:
1 import_name
- Flask程式所在的包(模塊),傳
__name__
就可以 - 其可以決定 Flask 在訪問靜態文件時查找的路徑
2 static_url_path
- 靜態文件訪問路徑,可以不傳,預設為:
/ + static_folder
3 static_folder
- 靜態文件存儲的文件夾,可以不傳,預設為
static
template_folder
- 模板文件存儲的文件夾,可以不傳,預設為
templates
預設參數情況下,訪問靜態資源
app = Flask(__name__)
修改參數的情況下,訪問靜態資源
# 定義靜態資源的訪問路徑為url_path_param,靜態資源文件夾名稱為folder_param
app = Flask(__name__, static_url_path='/url_path_param', static_folder='folder_param')
2.3.2 應用程式配置參數
Flask將配置信息保存到了app.config
屬性中,該屬性可以按照字典類型進行操作。
1 讀取配置參數
app.config.get(name)
app.config[name]
2 設置
Flask配置參數,主要使用以下三種方式:
從配置對象中載入
app.config.from_object(配置對象)
# 定義預設配置類
class DefultConfig(object):
"""
預設配置
"""
SECRET_KEY = "lalalalalala"
# 定義開發環境下的配置類,繼承自預設配置類
class DevDefultConfig(DefultConfig):
DEBUG=True
app = Flask(__name__)
# 從配置對象中添加配置
app.config.from_object(DefultConfig)
應用場景:
從配置文件中載入
app.config.from_pyfile(配置文件)
新建一個配置文件setting.py
SECRET_KEY = 'TPmi4aLWRbyVq8zu9v82dWYW1'
在Flask程式文件中讀取該配置文件
# 從配置文件中添加配置
app.config.from_pyfile("setting.py")
@app.route("/")
def index():
return app.config["SECRET_KEY"]
訪問測試
3 從環境變數中載入配置信息
環境變數(environment variables)一般是指在操作系統中用來指定操作系統運行環境的一些參數,如:臨時文件夾位置和系統文件夾位置等。
環境變數是在操作系統中一個具有特定名字的對象,它包含了一個或者多個應用程式所將使用到的信息。
通俗的理解,環境變數就是我們設置在操作系統中,由操作系統代為保存的變數值
Flask使用環境變數載入配置的本質是通過環境變數值找到配置文件,再讀取配置文件的信息,其使用方式為:
代碼查詢環境變數的方式:
# 環境變數中存儲的是配置文件的絕對地址
app.config.from_envvar('環境變數名')
兩種定義環境變數的方式
Windows環境下定義臨時環境變數
set 臨時環境變數名稱 = 變數的值
Pycharm下定義環境變數的方式
示例:
再運行程式,即可。
app = Flask(__name__)
app.config.from_envvar('PROJECT_SETTING', silent=True)
@app.route("/")
def index():
print(app.config['SECRET_KEY'])
return "hello world"
關於
silent
參數的說明:表示系統環境變數中沒有設置相應值時是否拋出異常
- False 表示不安靜的處理,沒有值時報錯通知,預設為False
- True 表示安靜的處理,即時沒有值也讓Flask正常的運行下去
訪問測試
項目中的常用方式
使用工廠模式創建Flask app,並結合使用配置對象與環境變數載入配置
- 使用配置對象載入預設配置
- 使用環境變數載入不想出現在代碼中的敏感配置信息
def create_flask_app(config):
"""
創建Flask應用
:param config: 配置對象
:return: Flask應用
"""
app = Flask(__name__)
app.config.from_object(config)
# 從環境變數指向的配置文件中讀取的配置信息會覆蓋掉從配置對象中載入的同名參數
app.config.from_envvar("PROJECT_SETTING", silent=True)
return app
方便了程式的使用,是一種常用的方式
2.3.3 app.run 參數
可以指定運行的主機IP地址,埠,是否開啟調試模式
app.run(host="0.0.0.0", port=5000, debug = True)
關於DEBUG調試模式
- 程式代碼修改後可以自動重啟伺服器
- 在伺服器出現相關錯誤的時候可以直接將錯誤信息返回到前端進行展示
2.4 開發伺服器啟動方式
在1.0版本之後,Flask調整了開發伺服器的啟動方式,由代碼編寫app.run()
語句調整為命令flask run
啟動。
from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
return 'Hello World'
# 程式中不用再寫app.run()
啟動
# 指定FLASK_APP環境變數(Windows CMD環境),demo01是文件名
set FLASK_APP=demo01
# 執行
flask run
說明
-
環境變數 FLASK_APP 指明flask的啟動實例
-
flask run -h 0.0.0.0 -p 8000
綁定地址 埠 -
flask run --help
獲取幫助 -
生產模式與開發模式的控制
通過
FLASK_ENV
環境變數指明set FLASK_ENV=production
運行在生產模式,未指明則預設為此方式set FLASK_ENV=development
運行在開發模式
擴展:指定參數運行
flask run --host 127.0.0.1 --port 6666
3 路由與藍圖
3.1 路由
3.1.1 查詢路由信息
需要提前設置好FLASK_APP
環境變數的值,並且cmd
處於管理員模式
命令行方式
flask routes
在程式中獲取
在應用中的url_map屬性中保存著整個Flask應用的路由映射信息,可以通過讀取這個屬性獲取路由信息
print(app.url_map)
在程式中遍歷路由信息
for rule in app.url_map.iter_rules():
print('name={} path={}'.format(rule.endpoint, rule.rule))
測試
實現通過訪問/routes
地址,以json的方式返回應用內的所有路由信息
import json
from flask import Flask
app = Flask(__name__)
@app.route("/flaskRoutes")
def getRoutes():
context = {}
for rule in app.url_map.iter_rules():
context[rule.endpoint] = rule.rule
return json.dumps(context)
3.1.2 指定請求方式
在 Flask 中,定義路由其預設的請求方式為:
- GET
- OPTIONS(自帶)
- HEAD(自帶)
利用methods
參數可以自己指定一個介面的多個請求方式,@app.get()
指定的是get
請求方式,@app.post()
指定的是post請求方式,以此類推
這裡只測試了兩個,其餘的基本相似(這裡採用的是Apifox進行測試)
3.2 藍圖
如果一個大的項目有多個模塊,在Flask中可以採用藍圖進行開發,對藍圖的理解可以對比Django中的子應用。在Flask中,使用藍圖Blueprint來分模塊組織管理。
3.2.1 藍圖的特點
藍圖實際可以理解為是一個存儲一組視圖方法的容器對象,其具有如下特點:
- 一個應用可以具有多個Blueprint
- 可以將一個Blueprint註冊到任何一個未使用的URL下比如 “/user”、“/goods”
- Blueprint可以單獨具有自己的模板、靜態文件或者其它的通用操作方法,它並不是必須要實現應用的視圖和函數的
- 在一個應用初始化時,就應該要註冊需要使用的Blueprint
但是一個Blueprint並不是一個完整的應用,它不能獨立於應用運行,而必須要註冊到某一個應用中。
3.2.2 藍圖的使用方式
使用藍圖可以分為三個步驟
-
創建一個藍圖對象
# 1.創建藍圖對象,兩個參數分別為藍圖名稱(name)和import_name user_bp =Blueprint('user',__name__)
-
在這個藍圖對象上進行操作,註冊路由,指定靜態文件夾,註冊模版過濾器
# 2.藍圖對象註冊路由 @user_bp.get("/user") def user_profile(): return "user_profile"
-
在應用對象上註冊這個藍圖對象
# 3.在app中註冊藍圖對象 app.register_blueprint(user_bp)
3.2.3 單文件藍圖
可以將創建藍圖對象與定義視圖放到一個文件中 ,也就是按照上面看到的代碼
3.2.4 目錄(包)藍圖
對於一個打算包含多個文件的藍圖,通常將創建藍圖對象放到Python包的__init__.py
文件中
--------- project # 工程目錄
|------ main.py # 啟動文件
|------ user #用戶藍圖
| |--- __init__.py # 此處創建藍圖對象
| |--- view.py
註意:如果不在
__init__.py
中導入view.py
文件,則會導致404
錯誤
3.2.5 擴展用法
1 指定藍圖的url首碼
在應用中註冊藍圖時使用url_prefix
參數指定首碼
app.register_blueprint(user_bp,url_prefix="/user")
2 藍圖內部靜態文件
和應用對象不同,藍圖對象創建時不會預設註冊靜態目錄的路由。需要我們在 創建時指定 static_folder 參數。
下麵的示例將藍圖所在目錄下的user_admin
目錄設置為靜態目錄
user_bp = Blueprint("user",__name__,static_folder="user_admin")
app.register_blueprint(user_bp,url_prefix="/user")
現在就可以使用/user/user_admin/<path:filename>
訪問user_admin
目錄下的靜態文件了。
也可通過static_url_path
改變訪問路徑
user_bp = Blueprint("user",__name__,static_folder="user_admin",static_url_path="static")
app.register_blueprint(user_bp,url_prefix="/user")
3 藍圖內部模板目錄
藍圖對象預設的模板目錄為系統的模版目錄,可以在創建藍圖對象時使用template_folder
關鍵字參數設置模板目錄
user_bp = Blueprint("user",__name__,
static_folder="user_admin",
static_url_path="static",
template_folder="templates")
4 請求與響應
4.1 處理請求
請求攜帶的數據可能出現在HTTP報文中的不同位置,需要使用不同的方法來獲取參數。
4.1.1. URL路徑參數(動態路由)
Flask不同於Django直接在定義路由時編寫正則表達式的方式,而是採用轉換器語法:
# 這裡本質上進行的是正則匹配
@app.route('/users/<user_id>')
def user_info(user_id):
print(type(user_id))
return 'hello user {}'.format(user_id)
此處的<>
即是一個轉換器,預設為字元串類型,即將該位置的數據以字元串格式進行匹配、並以字元串為數據類型類型、 user_id
為參數名傳入視圖。
Flask也提供其他類型的轉換器
DEFAULT_CONVERTERS = {
'default': UnicodeConverter,
'string': UnicodeConverter,
'any': AnyConverter,
'path': PathConverter,
'int': IntegerConverter,
'float': FloatConverter,
'uuid': UUIDConverter,
}
將上面的例子以整型匹配數據,可以如下使用:
@app.route('/users/<int:user_id>')
def user_info(user_id):
print(type(user_id))
return 'hello user {}'.format(user_id)
自定義轉換器
如果遇到需要匹配提取/users/18512345678
中的手機號數據,Flask內置的轉換器就無法滿足需求,此時需要自定義轉換器。
定義方法
自定義轉換器主要做3步
-
創建轉換器類,保存匹配時的正則表達式
from werkzeug.routing import BaseConverter # 1.自定義匹配手機號的轉換器 class PhoneConverter(BaseConverter): regex = "^1[3456789]\d{9}$"
- 註意
regex
名字固定
- 註意
-
註冊轉換器,將自定義的轉換器告知Flask應用
# 2. 註冊轉換器 app.url_map.converters["phone"] = PhoneConverter
-
使用轉換器:在使用轉換器的地方定義使用
@app.get('/users/phone/<phone:phoneNum>') def getPhone(phoneNum): return f"你的手機號是:{phoneNum}"
4.1.2. 其他參數
如果想要獲取其他地方傳遞的參數,可以通過Flask提供的request對象來讀取。
不同位置的參數都存放在request的不同屬性中
屬性 | 說明 | 類型 |
---|---|---|
data | 記錄請求的數據,並轉換為字元串 | * |
form | 記錄請求中的表單數據 | MultiDict |
args | 記錄請求中的查詢參數 | MultiDict |
cookies | 記錄請求中的cookie信息 | Dict |
headers | 記錄請求中的報文頭 | EnvironHeaders |
method | 記錄請求使用的HTTP方法 | GET/POST |
url | 記錄請求的URL地址 | string |
files | 記錄請求上傳的文件 | * |
例如 想要獲取請求/articles?channel_id=1
中channel_id
的參數,可以按如下方式使用:
@app.get("/request/change")
def getChangeId():
changeId = request.args.get("change_id")
return f"change_id = {changeId}"
上傳圖片
客戶端上傳圖片到伺服器,並保存到伺服器中
@app.post("/request/images")
def putImages():
image = request.files.get("image")
image.save("./Saber.png")
return "圖片上傳成功"
4.2 處理響應
4.2.1 返回模板
使用render_template
方法渲染模板並返回
# 其中template表示的是html模板的名稱,*kwargs是傳遞的參數
render_template(template,*kwargs)
實例:
測試:
4.2.2 重定向
from flask import redirect
@app.get("/redirectTest/")
def redirectTest():
return redirect("https://www.baidu.com/")
4.2.3 返回JSON
from flask import jsonify
@app.get("/jsonTest/")
def jsonTest():
json_dict = {
"user_id": 10086,
"user_name": "張三",
"user_age": 30
}
return jsonify(json_dict)
4.2.4 自定義狀態碼和響應頭
1 元組方式
可以返回一個元組,這樣的元組必須是
# 其中response為相應內容,status響應狀態碼,headers為響應頭的添加內容
(response, status, headers)
的形式,且至少包含一個元素。 status 值會覆蓋狀態代碼, headers 可以是一個列表或字典,作為額外的消息標頭值。
# 第一種自定義響應頭的方式
@app.get("/demoTestOne/")
def demoTestOne():
return ("狀態碼為 202",202)
2 make_response方式
@app.get("/demoTestTwo/")
def demoTestTwo():
resp = make_response("狀態碼為 201")
resp.headers['name'] = "zhangsan"
resp.status = 201
return resp
4.3 Cookie與Session
4.3.1 Cookie
1 設置Cookie
@app.get("/setCookie/")
def setCookie():
resp = make_response("set Cookie")
resp.set_cookie("username","zhangsan")
return resp
2 設置Cookie有效期
# 設置Cookie有效期
@app.get("/setCTime")
def setCTime():
resp = make_response("set cookie time")
resp.set_cookie("username","zhangsan",max_age=180)
return resp
3 讀取Cookie
# 讀取Cookie
@app.get("/getCookie")
def getCookie():
requ = request.cookies.get("username")
return f"username:{requ}"
4 刪除Cookie(實際是就是將有效期設置為0)
# 刪除Cookie
@app.get("/deleteCookie")
def deleteCookie():
resp = make_response("delete Cookie")
resp.delete_cookie("username")
return resp
4.3.2 Session
1 需要先設置SECRET_KEY
# 1 設置SECRET_KEY
class DefaultConfig(object):
SECRET_KEY = "zhansganlisiwangu"
app.config.from_object(DefaultConfig)
2 設置Session
# 2 設置Session
from flask import session
@app.get("/setSession/")
def setSession():
session['username'] = "username"
return "set Session"
3 讀取Session
@app.get("/getSession/")
def getSession():
username = session.get("username")
return f"get session username {username}"
這裡的Session並不是真正意義上的session,而是偽裝成Session的Cookie,因為它實際上並沒有將值存儲在伺服器上
5 請求鉤子與上下文
5.1 異常處理
5.1.1 HTTP 異常主動拋出
- abort 方法
- 拋出一個給定狀態代碼的 HTTPException 或者 指定響應,例如想要用一個頁面未找到異常來終止請求,你可以調用 abort(404)。
- 參數:
- code – HTTP的錯誤狀態碼
# abort(404)
abort(500)
拋出狀態碼的話,只能拋出 HTTP 協議的錯誤狀態碼
from flask import abort
@app.get("/getExcetion")
def getExcetion():
print("異常請求測試")
abort(500)
return "500異常測試"
5.1.2 捕獲錯誤
errorhandler
裝飾器
- 註冊一個錯誤處理程式,當程式拋出指定錯誤狀態碼的時候,就會調用該裝飾器所裝飾的方法
參數:
-
code_or_exception – HTTP的錯誤狀態碼或指定異常
-
例如統一處理狀態碼為500的錯誤給用戶友好的提示:
# 捕獲異常
@app.errorhandler(ZeroDivisionError)
def zero_division_error(e):
return "除數不能為0"
@app.get("/zeroTest")
def zeroDivision():
a = 10086/0
return f"結果是:{a}"
- 捕獲指定異常
@app.errorhandler(500)
def errorCode500():
return "嗚嗚嗚,伺服器出錯了,請稍後訪問"
@app.get("/getExcetion")
def getExcetion():
print("異常請求測試")
abort(500)
return "500異常測試"
5.2 請求鉤子
5.2.1 請求鉤子概念
在客戶端和伺服器交互的過程中,有些準備工作或掃尾工作需要處理,比如:
- 在請求開始時,建立資料庫連接;
- 在請求開始時,根據需求進行許可權校驗;
- 在請求結束時,指定數據的交互格式;
為了讓每個視圖函數避免編寫重覆功能的代碼,Flask提供了通用設施的功能,即請求鉤子。
請求鉤子是通過裝飾器的形式實現,Flask支持如下三種請求鉤子(before_first_request已經被廢止
):
1 before_request
- 在每次請求前執行
- 如果在某修飾的函數中返回了一個響應,視圖函數將不再被調用
2 after_request
- 如果沒有拋出錯誤,在每次請求後執行
- 接受一個參數:視圖函數作出的響應
- 在此函數中可以對響應值在返回之前做最後一步修改處理
- 需要將參數中的響應在此參數中進行返回
3 teardown_request
- 在每次請求後執行
- 接受一個參數:錯誤信息,如果有相關錯誤拋出
5.2.2 代碼測試
# 在每一次請求之前調用,這時候已經有請求了,可能在這個方法裡面做請求的校驗
# 如果請求的校驗不成功,可以直接在此方法中進行響應,直接return之後那麼就不會執行視圖函數
@app.before_request
def before_request():
print("before_request")
# 在執行完視圖函數之後會調用,並且會把視圖函數所生成的響應傳入,可以在此方法中對響應做最後一步統一的處理
@app.after_request
def after_request(response):
print("after_request")
response.headers["Content-Type"] = "application/json"
return response
# 請每一次請求之後都會調用,會接受一個參數,參數是伺服器出現的錯誤信息
@app.teardown_request
def teardown_request(response):
print("teardown_request")
# 測試請求
@app.route('/testRequest')
def index():
return 'index'
請求時列印的內容,可以看出,三個鉤子函數都被調用
5.3 上下文
上下文:即語境,語意,在程式中可以理解為在代碼執行到某一時刻時,根據之前代碼所做的操作以及下文即將要執行的邏輯,可以決定在當前時刻下可以使用到的變數,或者可以完成的事情。
Flask中有兩種上下文,請求上下文和應用上下文
Flask中上下文對象:相當於一個容器,保存了 Flask 程式運行過程中的一些信息。
5.3.1 請求上下文(request context)
在 flask 中,可以直接在視圖函數中使用 request 這個對象進行獲取相關數據,而 request 就是請求上下文的對象,保存了當前本次請求的相關數據,請求上下文對象有:request、session
1 request
- 封裝了HTTP請求的內容,針對的是
http
請求。舉例:user = request.args.get('user')
,獲取的是get請求的參數。
# request獲取請求參數
@app.get("/requestContext")
def requestContext():
user = request.args.get('user')
return f"你的名字是:{user}"
2 session
- 用來記錄請求會話中的信息,針對的是用戶信息。舉例:
session['name'] = user.id
,可以記錄用戶信息。還可以通過session.get('name')
獲取用戶信息。
# session存儲用戶id
@app.get("/setRequestSession")
def setRequestSession():
user_id = "zhangsan"
session['name'] = user_id
return "Session 設置成功"
# 獲取Session
@app.get("/getRequestSession")
def setRequestSession():
username = session.get('name')
return f"你的名字是:{username}"
5.3.2 應用上下文(application context)
它的字面意思是 應用上下文
,但它不是一直存在的,它只是request context
中的一個對app
的代理(人),所謂local proxy
。它的作用主要是幫助 request
獲取當前的應用,它是伴 request
而生,隨 request
而滅的。
應用上下文對象有:current_app
,g
1 current_app
應用程式上下文,用於存儲應用程式中的變數,可以通過current_app.name
列印當前app
的名稱,也可以在current_app
中存儲一些變數,例如:
- 應用的啟動腳本是哪個文件,啟動時指定了哪些參數
- 載入了哪些配置文件,導入了哪些配置
- 連了哪個資料庫
- 有哪些public的工具類、常量
- 應用跑再哪個機器上,
IP
多少,記憶體多大
示例
創建current_app_demo.py
from flask import current_app
app1 = Flask(__name__)
app2 = Flask(__name__)
app1.redis_cli = 'app1 redis client'
app2.redis_cli = 'app2 redis client'
@app1.route('/route11')
def route11():
# current_app獲取的是當前正在使用的app
return current_app.redis_cli
@app2.route('/route21')
def route21():
return current_app.redis_cli
運行
set FLASK_APP=main:app1
flask run
set FLASK_APP=main:app2
flask run
作用
current_app
就是當前運行的flask app
,在代碼不方便直接操作flask的app對象時,可以操作current_app
就等價於操作flask app
對象,而不會出現app
調用app
對象自身導致的迴圈依賴問題
2 g對象
g
作為flask
程式全局的一個臨時變數,充當中間媒介的作用,我們可以通過它在一次請求調用的多個函數間傳遞一些數據。每次請求都會重設這個變數。
示例
from flask import g
def query():
user_id = g.user_id
user_name = g.user_name
return f"userid={user_id},name={user_name},已執行內部函數"
@app.post("/getUser/")
def get_user():
userid = request.args.get("userid")
username = request.args.get("username")
g.user_id = userid
g.user_name = username
text = query()
return text
5.3.3 app_context 與 request_context
思考
在Flask程式未運行的情況下,調試代碼時需要使用current_app
、g
、request
這些對象,該如何進行測試。
1 app_context
app_context
為我們提供了應用上下文環境,允許我們在外部使用應用上下文curren
t_app、
g`
可以通過with
語句進行使用
>>> from flask import Flask
>>> app = Flask('')
>>> app.redis_cli = 'redis client'
>>>
>>> from flask import current_app
>>> current_app.redis_cli # 錯誤,沒有上下文環境
報錯
>>> with app.app_context(): # 藉助with語句使用app_context創建應用上下文
... print(current_app.redis_cli)
...
redis client
2 request_context
request_context
為我們提供了請求上下文環境,允許我們在外部使用請求上下文request
、session
可以通過with語句進行使用
>>> from flask import Flask
>>> app = Flask('')
>>> request.args # 錯誤,沒有上下文環境
報錯
>>> environ = {'wsgi.version':(1,0), 'wsgi.input': '', 'REQUEST_METHOD': 'GET', 'PATH_INFO': '/', 'SERVER_NAME': 'itcast server', 'wsgi.url_scheme': 'http', 'SERVER_PORT': '80'} # 模擬解析客戶端請求之後的wsgi字典數據
>>> with app.request_context(environ): # 藉助with語句使用request_context創建請求上下文
... print(request.path)
6 Flask-RESTful
6.1 起步
Flask-RESTful是用於快速構建REST API的Flask擴展。
6.1.1 安裝
pip install flask-restful
6.1.2 Hello World
from flask import Flask
from flask_restful import Resource,Api
app = Flask(__name__)
api = Api(app)
class HelloWordResource(Resource):
def get(self):
return {"hello":"world"}
def post(self):
return {"msg":"post Hello,World"}
api.add_resource(HelloWordResource,"/hello")
# 也可以選擇flask run的啟動方式
if __name__=="__main__":
app.run(debug=True)
6.2 關於視圖
6.2.1 為路由起名
通過endpoint參數為路由起名
# 這個名稱在後續會用到
api.add_resource(HelloWorldResource, '/', endpoint='HelloWorld')
6.2.2 藍圖中使用
# 1 定義藍圖
user_bp = Blueprint('user',__name__,url_prefix="/user")
# 2 api配置藍圖
user_api = Api(user_bp)
# 3 app配置藍圖
app.register_blueprint(user_bp)
# 4 定義藍圖請求
class UserBlueResource(Resource):
def get(self):
context = {
"massage":2001,
"data":{
"name":"zhangsan",
"age":16
}
}
return context
def post(self):
context = {
"massage":2001,
"data":{
"name":"This is post Man",
"age":"*****(查看請充值vip)"
}
}
return context
# 5 配置api路由
user_api.add_resource(UserBlueResource,"/blueUser")
6.2.3 裝飾器
使用method_decorators
添加裝飾器
為類視圖中的所有方法添加裝飾器
def decorator1(func):
def wrapper(*args, **kwargs):
print('裝飾器1正在執行')
return func(*args, **kwargs)
return wrapper
def decorator2(func):
def wrapper(*args, **kwargs):
print('裝飾器2正在執行')
return func(*args, **kwargs)
return wrapper
class DemoRequest(Resource):
method_decorators = [decorator1,decorator2]
def get(self):
context = {
"msg":200,
"data":{
"text":"一切正常"
}
}
return context
def post(self):
context = {
"msg":200,
"data":{
"text":"I am PostMax"
}
}
return context
api.add_resource(DemoRequest,"/demo")
為類視圖中不同的方法添加不同的裝飾器
class DemoResource(Resource):
method_decorators = {
'get': [decorator1, decorator2],
'post': [decorator1]
}
# 使用了decorator1 decorator2兩個裝飾器
def get(self):
return {'msg': 'get view'}
# 使用了decorator1 裝飾器
def post(self):
return {'msg': 'post view'}
# 未使用裝飾器
def put(self):
return {'msg': 'put view'}
get請求測試
post請求測試
put請求測試
6.3 關於請求
6.3.1 概述
Flask-RESTful
提供了RequestParser
類,用來幫助我們檢驗和轉換請求數據。
6.3.2 使用步驟:
-
創建
RequestParser
對象 -
向
RequestParser
對象中添加需要檢驗或轉換的參數聲明 -
使用
parse_args()
方法啟動檢驗處理 -
檢驗之後從檢驗結果中獲取參數時可按照字典操作或對象屬性操作
args.rate 或 args['rate']
6.3.3 參數說明
1 required
描述請求是否一定要攜帶對應參數,預設值為False
-
True 強制要求攜帶
若未攜帶,則校驗失敗,向客戶端返回錯誤信息,狀態碼400
-
False 不強制要求攜帶
若不強制攜帶,在客戶端請求未攜帶參數時,取出值為None
from flask_restful.reqparse import RequestParser
class rqparseRequest(Resource):
# 1 required 參數測試
def get(self):
rqp = RequestParser()
# 強制要求攜帶該參數
rqp.add_argument("user",required=True)
args = rqp.parse_args()
return {"message":200,"data":{"user":args.user}}
api.add_resource(rqparseRequest,"/rpone")
2 help
參數檢驗錯誤時返回的錯誤描述信息
from flask_restful.reqparse import RequestParser
class rqparseRequest(Resource):
# 2 help參數測試
def post(self):
rqp = RequestParser()
# 強制要求攜帶該參數
rqp.add_argument("user",required=True,help="沒有user參數")
args = rqp.parse_args()
return {"message":200,"data":{"user":args.user}}
api.add_resource(rqparseRequest,"/rpone")
3 action
描述對於請求參數中出現多個同名參數時的處理方式
action='store'
保留出現的第一個, 預設action='append'
以列表追加保存所有同名參數的值
from flask_restful.reqparse import RequestParser
class rqparseRequest(Resource):
# 3 action參數測試
def put(self):
rp = RequestParser()
rp.add_argument("user",required=True,action="append")
args = rp.parse_args()
return {"message": 200, "data": {"user": args.user}}
api.add_resource(rqparseRequest,"/rpone")
4 type
描述參數應該匹配的類型,可以使用python的標準數據類型string、int,也可使用Flask-RESTful
提供的檢驗方法,還可以自己定義
-
標準類型
from flask_restful.reqparse import RequestParser class rqparseRequest(Resource): # 4 type參數測試 def delete(self): rp = RequestParser() rp.add_argument("user",required=True,type=int) args = rp.parse_args() return {"message": 200, "data": {"user": args.user}} api.add_resource(rqparseRequest,"/rpone")
-
Flask-RESTful提供
檢驗類型方法在
flask_restful.inputs
模塊中-
url
-
regex(指定正則表達式)
from flask_restful import inputs class rqparseRequestTwo(Resource): # Flask指定的檢驗格式 def get(self): rp = RequestParser() rp.add_argument('user', type=inputs.regex(r'^1[3-9]\d{9}$')) args = rp.parse_args() return {"message": 200, "data": {"user": args.user}} api.add_resource(rqparseRequestTwo,"/rptwo")
-
natural
自然數0、1、2、3... -
positive
正整數 1、2、3... -
int_range(low ,high)
整數範圍rp.add_argument('a', type=inputs.int_range(1, 10))
-
boolean
-
-
自定義
def mobile(mobile_str): """ 檢驗手機號格式 :param mobile_str: str 被檢驗字元串 :return: mobile_str """ if re.match(r'^1[3-9]\d{9}$', mobile_str): return mobile_str else: raise ValueError('{} is not a valid mobile'.format(mobile_str)) rp.add_argument('a', type=mobile)
5 location
描述參數應該在請求數據中出現的位置
# Look only in the POST body
parser.add_argument('name', type=int, location='form')
# Look only in the querystring
parser.add_argument('PageSize', type=int, location='args')
# From the request headers
parser.add_argument('User-Agent', location='headers')
# From http cookies
parser.add_argument('session_id', location='cookies')
# From json
parser.add_argument('user_id', location='json')
# From file uploads
parser.add_argument('picture', location='files')
也可指明多個位置
parser.add_argument('text', location=['headers', 'json'])
測試
from flask_restful import inputs
class rqparseRequestTwo(Resource):
# location測試
def post(self):
parser = RequestParser()
# form表單
parser.add_argument('name', type=int, location='form')
# 位置參數
parser.add_argument('PageSize', type=int, location='args')
args = parser.parse_args()
return {"message": 200, "data": {"name": args.name,"PageSize": args.PageSize}}
api.add_resource(rqparseRequestTwo,"/rptwo")
6.4 關於響應
6.4.1 序列化數據
Flask-RESTful
提供了marshal
工具,用來幫助我們將數據序列化為特定格式的字典數據,以便作為視圖的返回值。
# 1 導包
from flask_restful import Resource,fields,marshal_with,marshal
# 2 定義類
class Book(object):
def __init__(self,bookName,author):
self.bookName = bookName
self.author = author
# 3 定義模板
resource_fields = {
'bookName':fields.String,
"author":fields.String
}
# 4 定義返回函數
class BookTodo(Resource):
# 使用裝飾器實現
@marshal_with(resource_fields,envelope="context")
def get(self):
# 對象無法直接返回,這個裝飾器相當於將對象序列化了
book = Book("《射雕英雄傳》","金庸")
return book
api.add_resource(BookTodo,"/booktodo")
也可以不使用裝飾器的方式
# 不使用裝飾器,而是調用函數實現
def post(self):
book = Book("《射雕英雄傳》","金庸")
return marshal(book,resource_fields