1、聊聊Flask框架
Flask官方文檔
??Flask是Armin ronacher基于Python開發(fā)的微型Web框架,誕生于2010年,它依賴于jinja2模板和Werkzeug WSGI服務(wù)。Flask的核心簡(jiǎn)單易于擴(kuò)展,它不會(huì)替你做出太多決策比如使用何種數(shù)據(jù)庫(kù)或模板引擎,這些都可以根據(jù)自己的需求進(jìn)行選擇和替換。Flask的設(shè)計(jì)理念是讓發(fā)人員可以根據(jù)自己的需求進(jìn)行自定義,同時(shí)提供足夠的靈活性和可擴(kuò)展性。
2、Falsk常用第三方擴(kuò)展包
可在Flask官方文檔的擴(kuò)展包頁(yè)面中找到許多常用的Flask擴(kuò)展包。
插件 | 功能 |
---|---|
Flask-SQLAlchem | 使用SQLAlchemy ORM |
Flask-Login | 處理用戶認(rèn)證和會(huì)話管理 |
Flask-Uploads | 處理文件上傳 |
Flask-Admin | 構(gòu)建管理界面 |
Flask-WTF | 處理Web表單 |
Flask-RESTful | 構(gòu)建RESTful API |
Flask-Mail | 發(fā)送電子郵件 |
Flask-Caching | 緩存數(shù)據(jù) |
Flask-Jwt-Extended | 處理JSON Web Tokens |
Flask-SocketIO | 處理WebSocket通信 |
Flask-Migrate | 處理數(shù)據(jù)庫(kù)遷移 |
Flask-Assets | 處理靜態(tài)資源 |
Flask-Cors | 實(shí)現(xiàn)跨域 |
Flask-Bcrypt | 實(shí)現(xiàn)加密 |
3、Flask鉤子函數(shù)
鉤子函數(shù) | 執(zhí)行時(shí)間 | 特別說明 |
---|---|---|
before_first_request | 項(xiàng)目初始化時(shí)的鉤子 | |
before_request | 在每次請(qǐng)求前執(zhí)行 | |
after_reauest | 如果沒有拋出錯(cuò)誤,在每次請(qǐng)求后執(zhí)行 | 接收視圖函數(shù)做出的響應(yīng) |
teardown_request | 在每次請(qǐng)求后執(zhí)行 | 接收錯(cuò)誤信息,如果有相關(guān)錯(cuò)誤拋出 |
4、Flask路由
路由和視圖的名稱必須全局統(tǒng)一,不能出現(xiàn)重復(fù),否則報(bào)錯(cuò)
4.1 flask默認(rèn)支持的轉(zhuǎn)換器
名稱 | 描述 |
---|---|
string | 默認(rèn)類型,接受不帶斜杠的任何文本 |
int | 接受正整數(shù) |
float | 接受正浮點(diǎn)值 |
path | 接收string但也接受斜線 |
uuid | 接受UUID字符串 |
4.2 任意路由參數(shù)
# 不限定類型
@app.route('/user/<params>')
def user_info(params):
return 'params %s' % params
# 限定數(shù)據(jù)類型 中間不能有空格
@app.route('/user/<int:uid>')
def user_info(uid):
return 'uid %d' % uid
4.3 自定義路由轉(zhuǎn)換器
from werkzeug.routing import BaseConverter
class MobileConverter(BaseConverter):
"""check mobile"""
def __init__(self,map,*args):
super().__init__(map)
self.regex = "1[3-9]\d{9}"
app.url_map.converters['mobile'] = MobileConverter
@app.route('/user/<mobile:mobile>', methods=['get', 'post'])
def test_view(mobile):
return mobile
5、HTTP請(qǐng)求與響應(yīng)
flask中使用request獲取當(dāng)前請(qǐng)求的對(duì)象
5.1 請(qǐng)求
獲取常用的請(qǐng)求信息:
信息 | 描述 | 示例 |
---|---|---|
request.method | 請(qǐng)求的HTTP方法 | GET, POST, PUT, DELETE等等 |
request.url | 請(qǐng)求的完整URL | http://example.com/path?query=string |
request.headers | 請(qǐng)求頭部的字典形式 | {‘Content-Type’: ‘a(chǎn)pplication/json’} |
request.args | URL中的查詢參數(shù) | {‘key’: ‘value’} |
request.form | 表單數(shù)據(jù) | {‘username’: ‘john’, ‘password’: ‘123’} |
request.files | 上傳的文件 | {‘file’: } |
request.cookies | 請(qǐng)求中的Cookie | {‘session_id’: ‘a(chǎn)bc123’} |
request.remote_addr | 客戶端的IP地址 | 127.0.0.1 |
request.user_agent | 發(fā)起請(qǐng)求的UA | Mozilla/5.0 … |
request.json | Json格式的請(qǐng)求體數(shù)據(jù) | {‘key’: ‘value’} |
request.data | 請(qǐng)求體的原始數(shù)據(jù)(字節(jié)形式) | b’raw data’ |
獲取請(qǐng)求示例:
from flask import request, jsonify
from application.apps.index import index_blueprint
@index_blueprint.route("/index")
def index():
data = request.get_json()
# 數(shù)據(jù)處理...
return jsonify(data='welcome flask!'), 200
5.2 響應(yīng)
flask默認(rèn)支持兩種數(shù)據(jù)響應(yīng)和頁(yè)面響應(yīng)
數(shù)據(jù)響應(yīng)
from flask import make_response, jsonify
@app.route("/")
def index():
# 默認(rèn)響應(yīng)html
return '<h1>hello world!</h1>'
# 響應(yīng)html
return make_response('<h1>hello world!</h1>')
# 響應(yīng)json
return jsonify(msg='hello world!')
頁(yè)面響應(yīng)
from flask import redirect
@app.route("/")
def handle_request():
# 重定向
return redirect("http://www.example.com")
# 視圖方法內(nèi)部跳轉(zhuǎn)
return redirect(url_for("view funcname"))
# 視圖方法內(nèi)部跳轉(zhuǎn)攜帶參數(shù)
return redirect(url_for("view funcname", params-name=''))
自定義http響應(yīng)內(nèi)容
from flask import make_response
@app.route("/")
def handle_request():
response = Response('Custom Response')
response.headers['Content-Type'] = 'text/plain'
response.status_code = 200
return response
6、異常捕獲
6.1 主動(dòng)拋出異常
可以使用abort方法拋出一個(gè)給定的狀態(tài)碼的HTTPException或者指定響應(yīng),一般用于權(quán)限校驗(yàn)等頁(yè)面上錯(cuò)誤展示
# 參數(shù)HTTP狀態(tài)碼
abort(500)
6.2 捕獲自定義異常
初始化app的時(shí)候可以將捕獲異常的方法注冊(cè),也可以使用裝飾器
def exception_method_not_allow(error):
logging.error("An exception occurred: {}".format(str(error)))
return jsonify(msg='method not allowed'), 405
# 第一個(gè)參數(shù)可以是異常類型或者狀態(tài)碼
app.register_error_handler(405, exception_method_not_allow)
# 捕獲自定義異常
@app.errorhandler(ZeroDivisionError)
def zero_division_error(e):
return '除數(shù)不能為0'
7、context
??執(zhí)行上下文:即語(yǔ)境,語(yǔ)意,在程序中可以理解為在代碼執(zhí)行到某一行時(shí),根據(jù)之前代碼所做的操作以及下文即將要執(zhí)行的邏輯,可以決定在當(dāng)前時(shí)刻下可以使用到的變量,或者可以完成的事情。Flask中上下文對(duì)象:相當(dāng)于一個(gè)容器,保存了程序運(yùn)行過程中的變量、函數(shù)、類與對(duì)象等信息。Flask中有請(qǐng)求上下文和應(yīng)用上下文。
- 請(qǐng)求:發(fā)生http請(qǐng)求時(shí),調(diào)用
Flask.__call__()
之后,在Flask
對(duì)象內(nèi)部創(chuàng)建的Request
對(duì)象; - 應(yīng)用:調(diào)用
app = Flask(__name__)
創(chuàng)建的這個(gè)對(duì)象app
,
7.1 請(qǐng)求上下文
??在flask中,可以直接在視圖函數(shù)中使用request這個(gè)對(duì)象進(jìn)行獲取相關(guān)數(shù)據(jù),request就是請(qǐng)求上下文的對(duì)象,保存了當(dāng)前本次請(qǐng)求的相關(guān)數(shù)據(jù),請(qǐng)求上下文對(duì)象有:request、session。
??request封裝了HTTP請(qǐng)求的內(nèi)容,針對(duì)的是http請(qǐng)求。session用來記錄用戶會(huì)話中的信息。
7.2 應(yīng)用上下文
??應(yīng)用上下文,它不是一直存在的,只是request context 中操作當(dāng)前falsk應(yīng)用對(duì)象app的代理(local proxy)。它的作用主要是幫助 request 獲取當(dāng)前的flask應(yīng)用相關(guān)的信息,它是伴request而生,隨request 而滅的。
??current_app是應(yīng)用程序上下文,用于存儲(chǔ)應(yīng)用程序中的變量,可以通過current_app.name打印當(dāng)前app的名稱,也可以在current_app中存儲(chǔ)一些變量,例如:
- 應(yīng)用的啟動(dòng)腳本是哪個(gè)文件,啟動(dòng)時(shí)指定了哪些參數(shù)
- 加載了哪些配置文件,導(dǎo)入了哪些配置
- 連接了哪個(gè)數(shù)據(jù)庫(kù)
- 有哪些可以調(diào)用的工具類、常量
- 當(dāng)前flask應(yīng)用在哪個(gè)機(jī)器上,哪個(gè)IP上運(yùn)行,內(nèi)存多大
from flask import current_app
def index():
print(current_app.config) # 獲取當(dāng)前項(xiàng)目的所有配置信息
print(current_app.url_map) # 獲取當(dāng)前項(xiàng)目的所有路由信息
return "<h1>hello world!</h1>"
7.3 g對(duì)象
??g對(duì)象是flask程序全局的一個(gè)臨時(shí)變量,充當(dāng)者中間媒介的作用,我們可以通過它傳遞一些數(shù)據(jù),g對(duì)象保存的是當(dāng)前請(qǐng)求的全局變量,不同的請(qǐng)求會(huì)有不同的全局變量,通過不同的thread-id區(qū)別。
from flask import Flask, g
app = Flask(__name__)
@app.before_request
def before_request():
g.name = "root"
@app.route(rule='/')
def index():
print(g.name) # 獲取到全局變量root
return "<h1>hello world!</h1>"
if __name__ == '__main__':
app.run()
8、藍(lán)圖 Blueprint
??Blueprint是一個(gè)存儲(chǔ)視圖方法的容器,這些操作在這個(gè)Blueprint被注冊(cè)到一個(gè)應(yīng)用之后就可以被調(diào)用,F(xiàn)lask可以通過Blueprint來組織URL以及處理請(qǐng)求。Flask使用Blueprint讓應(yīng)用實(shí)現(xiàn)模塊化,Blueorint具有如下屬性:
- 一個(gè)項(xiàng)目可以具有多個(gè)Blueprint
- 可以將一個(gè)Blueprin注冊(cè)到任何一個(gè)未使用的URL下比如"/“、”/api"或者子域名
- 在一個(gè)應(yīng)用中,一個(gè)模塊可以注冊(cè)多次
- Blueorint可以單獨(dú)具有自己的模板、靜態(tài)文件或者其它的通用操作方法
- 在一個(gè)應(yīng)用初始化時(shí),就應(yīng)該要注冊(cè)需要使用的Blueprint
8.1 藍(lán)圖使用
示例可以通過:
http://127.0.0.1:5000/api/v1/index
訪問到藍(lán)圖中定義的視圖函數(shù)
# 創(chuàng)建一個(gè)藍(lán)圖模塊
# __init__.py
from flask import Blueprint
index_blueprint = Blueprint("index_blueprint", __name__)
from application.apps.index.view import *
# views.py
from flask import jsonify
from application.apps.index import index_blueprint
@index_blueprint.route("/index")
def index():
return jsonify(data='welcome flask!'), 200
# 注冊(cè)藍(lán)圖到應(yīng)用
app.register_blueprint(index_blueprint, url_prefix='/api/v1')
8.2 運(yùn)行機(jī)制
- 藍(lán)圖是保存了一組將來可以在應(yīng)用app對(duì)象上執(zhí)行的操作,注冊(cè)路由就是一種操作
- 當(dāng)在app對(duì)象上調(diào)用route裝飾器注冊(cè)路由時(shí),這個(gè)操作將修改對(duì)象的url_map路由表
- 然而,藍(lán)圖對(duì)象根本沒有路由表,當(dāng)我們?cè)谒{(lán)圖對(duì)象上調(diào)用route裝飾器注冊(cè)路由時(shí),它只是在內(nèi)部的一個(gè)延遲操作記錄列表defered_functions中添加了一個(gè)項(xiàng)
- 當(dāng)執(zhí)行了app對(duì)象的register_blueprint()方法時(shí),app應(yīng)用對(duì)象將從藍(lán)圖對(duì)象的defered_functions列表中取出每一項(xiàng),并以自身作為參數(shù)執(zhí)行該匿名函數(shù),即調(diào)用app應(yīng)用對(duì)象的add_url_rule()方法,將藍(lán)圖的路由信息全部注冊(cè)到應(yīng)用對(duì)象app的url_map路由表
8.3 藍(lán)圖靜態(tài)文件
??和app應(yīng)用對(duì)象不同,藍(lán)圖對(duì)象創(chuàng)建時(shí)不會(huì)默認(rèn)注冊(cè)靜態(tài)目錄的路由。需要我們?cè)趧?chuàng)建時(shí)指定static_folder
參數(shù)。下面的示例將藍(lán)圖所在目錄下的static_home目錄設(shè)置為靜態(tài)目錄。有了藍(lán)圖的靜態(tài)目錄以后,并不會(huì)影響原來項(xiàng)目中提供的static總靜態(tài)文件目錄的使用。
# index/__init__.py
from flask import Blueprint
index_blueprint = Blueprint("index_blueprint", __name__, static_folder="static_index")
9、實(shí)現(xiàn)異步
??如果在安裝 Flask 時(shí)使用了額外的 async
( 即用 pip install flask[async]
命令安裝),那么路由、出錯(cuò)處理器、請(qǐng)求前、請(qǐng) 求后和拆卸函數(shù)都可以是協(xié)程函數(shù)。這樣,視圖可以使用 async
定義,并使用 await
。
import logging
import asyncio
from flask import jsonify
from application.apps.index import index_blueprint
from application.extensions import redis_cli
@index_blueprint.route("/index")
async def index():
# 模擬耗時(shí)
await asyncio.sleep(1)
return jsonify(data='welcome flask!'), 200
9.1 性能
??異步函數(shù)需要一個(gè)事件循環(huán)來運(yùn)行。 Flask作為WSGI應(yīng)用,使用一個(gè)worker來處理一個(gè)請(qǐng)求響應(yīng)周期。當(dāng)請(qǐng)求進(jìn)入異步視圖時(shí), Flask會(huì)在一個(gè)線程中啟動(dòng)一個(gè)事件循環(huán),在其中運(yùn)行視圖函數(shù),然后返回結(jié)果。即使對(duì)于異步視圖,每個(gè)請(qǐng)求仍然會(huì)綁定一個(gè)worker。好處是您可以在一個(gè)視圖內(nèi)運(yùn)行異步代碼,例如多個(gè)并發(fā)數(shù)據(jù)庫(kù)查詢,對(duì)外部API的HTTP請(qǐng)求,等等。但是,應(yīng)用程序可以處理的請(qǐng)求并發(fā)數(shù)量將保持不變。
??異步本質(zhì)上并不比同步快。 在執(zhí)行并發(fā)IO綁定任務(wù)時(shí), 異步是有益的。但是對(duì)于CPU密集型任務(wù),則未必有用,因此傳統(tǒng)的Flask視圖仍然適用于大多數(shù)用例。 Flask異步支持的引入,帶來本地化編寫和使用異步代碼的可能性。
10、搭建一個(gè)合理的項(xiàng)目架構(gòu)
適合一個(gè)中型項(xiàng)目使用,區(qū)分模塊,區(qū)分環(huán)境
文章來源:http://www.zghlxwxcb.cn/news/detail-476504.html
11、 總結(jié)
??從 Flask 0.11 開始,F(xiàn)lask已經(jīng)內(nèi)置了一個(gè)命令行工具,因此不再需要使用Flask-Script,會(huì)產(chǎn)生包不兼容的問題。使用flask manage.py方式啟動(dòng)項(xiàng)目應(yīng)該執(zhí)行export FLASK_APP=manage.py,指定flask入口文件,另外,flask-sqlalchemy是flask的ORM工具,參考SqlAlchemy使用入門。文章來源地址http://www.zghlxwxcb.cn/news/detail-476504.html
到了這里,關(guān)于使用Flask高效構(gòu)建Web應(yīng)用的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!