微信搜尋【大奇測試開】,關注這個堅持分享測試開發乾貨的傢伙。
本篇主要是對之前幾次分享的階階段的總結,溫故而知新,況且雖然看起來是一個小模組簡單的增刪改查操作,但其實涉及的內容點是非常的密集的,是非常基礎的,也貫穿了整個流程,後續的模組開發操作在掌握這幾篇基礎上會很快速,如果你還沒看過之前的內容,可以參照下邊往期閱讀進行學習,不過這不影響單純你想看看如何用python Flask實現常用的Resufl API。
================ 往期推薦 ==================
- 【提測平臺】分享3-正式開發產品需求&專案初始化
- 【提測平臺】分享4-實現資料庫繫結和產品線顯示功能
- 【提測平臺】分享5-實現產品線的新增
- 【提測平臺】分享6-產品線修改和軟硬刪除功能實現
- 【提測平臺】分享7-實現產品搜尋和優化時間顯示
=============================================
Flask 一個python的web架構服務,實現前後端的開發,在本專案主要是使用它的 Resful API 實現能能力,雖說頁面能力可以通過jinjia實現,但當今有更簡單,好用的類似vue這樣的開箱即用的開源框架,因此做到前後端分離,讓它發揮好後端介面能力就好了,當然還有一些其他優秀的框架比如tornado、django、bootstrap等等,但基於介面和此專案flask更為合適。
現在就著分享專案來總結下Flask已經使用過的一些基礎能力,以及再做一些擴充套件。
Flask程式入口
一個最小的 Flask 應用,也是程式程式碼的執行起點,檔名app.py
from flask import Flask app = Flask(__name__) @app.route("/api/sayHello/") def hello_world(): return "Hello, TPM!" if __name__ == '__main__': app.run()
這一小段程式碼最簡單的實現了一個預設的GET請求介面 /api/sayHello,沒有請求引數,返回的是一個“Hello,TPM”字串。
-
首先是引入Flask類
-
然後建立了該類的一個例項,該例項將成為一個Web伺服器閘道器介面( Python Web Server Gateway Interface,縮寫為 WSGI )應用
-
使用 裝飾器 route() 來告訴 Flask 觸發函式 的 URL ,預設HTTP請求方法為GET型別
-
被修飾的方法實現返回一個字串,預設返回 text/htm 型別
-
Python程式的主方法,程式執行入口(次程式碼中省略也可以執行)
理解上邊的程式碼後,開啟一個終端,執行方法 $ flask run 啟動應用,瀏覽器地址輸入 http://127.0.0.1:5000/ 即可看到返回的字串 “Hello,TPM!”
app.run() 還涉及到幾個引數,擴充套件介紹下,如果你使用類似PyCharmm開發工具,使用command + 滑鼠左鍵 就可以點選跳轉方法的實現,方法如下,如果英文好的可以直接官方解釋。
def run(self, host=None, port=None, debug=None, load_dotenv=True, **options):
這裡可以設定引數分別是host-指定IP,port-指定埠,debug-除錯模式
-
host設定
預設的host為本地地址127.0.0.1 只能本地訪問除錯,如果區域網其他機器允許訪問,就需要設定host=本機IP,或者host=0.0.0.0讓其自行識別
-
port設定
預設port為5000埠,如果想用其他埠需要給定此引數如port=8082
-
debug設定
通過debug=True設定除錯模式,這樣每次有程式碼修改儲存時程式會自動重新熱載入,不需要每次重新啟動。
一個簡單的配置如下:
app.run(host="0.0.0.0", port=8082, debug=True)
這裡需要特別注意的是,方法配置必須使用 python3 app.py 去啟動程式,如果是用上述 flask run 命令或者PyCharm啟動,方法裡設定引數是無效的,需要通過指定引數 flask run --host=0.0.0.0 --port=8082 或者配置引數
Flask的路由和HTTP方法
路由顧名思義就是給定請求路徑,在最小應用的例子中已經說過是通過route() 裝飾器 設定URL,方法就是給定第一個字串引數如“/api/project/select”,至於如何配置引數規則下邊具體講。
HTTP方法 在Flask框架實現【提測平臺】介面專案中分別使用了GET、POST、Delete三種常用的請求方法,其實現在業界開發(不管什麼語言)使用最頻繁的時候GET/POST兩種,基本解決所有操作。
定義介面的請求方法也很簡單就是在路由內指定引數 methods=['方法']
@app.route("/api/product/search",methods=['GET']) def product_search(): return "GET介面請求查詢產品操作" @app.route("/api/product/create",methods=['POST']) def product_create(): return "POST介面請求新增產品操作" @app.route("/api/product/delete", methods=['DELETE']) def product_delete(): return "Delete介面請求新增產品操作"
這些程式碼加在最小程式app.py重新執行後(debug=True自動重新載入),用Postman分別用對應的方法請求,都會正常返回return中的給定的字串內容,這裡可以嘗試下如果一個介面設定了POST型別,如果測試用其他型別,則會返回 405 Method Not Allowed 表示不被允許的請求方法。
我們注意到methods=[]是個陣列,所以我們可以對一個api指定多種型別的,比如給定GET和POST這樣客戶端用對應哪種方法請求都會正常返回值。
@app.route("/api/product/list",methods=['GET','POST']) def product_list(): return "我支援GET和POST兩種"
Flask介面模組化
從上邊的定義很多介面可以看到我們所有的定義都編寫在主程式類裡,這樣對於稍微複雜的應用程式程式碼就會很臃腫,現在程式設計都都講究各種模式或者分模組程式設計,那麼教程專案中 blueprints (網路中文譯為藍圖)就是這個作用,以上邊的例子來優化,將所有/api/product/* 的介面全部抽出來放到一個product.py 檔案中,並定義一個別名為app_product 藍圖。
from flask import Blueprint app_product = Blueprint("app_product", __name__) @app_product.route("/api/product/search",methods=['GET']) def product_search(): return "GET介面請求查詢產品操作" @app_product.route("/api/product/create",methods=['POST']) def product_create(): return "POST介面請求新增產品操作" @app_product.route("/api/product/delete", methods=['DELETE']) def product_delete(): return "Delete介面請求新增產品操作" @app_product.route("/api/product/list",methods=['GET','POST']) def product_list(): return "我支援GET和POST兩種"
接著就要在app.py 註冊blueprint,儲存自動執行
from flask import Flask # 匯入模組類 from apis.products import app_product app = Flask(__name__) # 註冊blueprint app.register_blueprint(app_product) @app.route("/api/sayHello/") def hello_world(): return "Hello, TPM!" if __name__ == '__main__': app.run(host='0.0.0.0', port=8082, debug=True)
再次通過postman請求之前幾個介面,一切正常,但看上去是不是清爽很多。
同樣我們跳轉blueprints.py原始碼檢視 __init__ 方法還有不少引數,比如url_prefix="/api/product" 定義統一URL字首,那麼在 route 路徑定義都可以去掉相同的字首路徑/api/product,這樣更清爽了,至於其他引數後續涉及到再講解,或者直接原始碼。
Flask介面引數
本篇總結和擴充套件最後一個知識點,就是客戶端傳參和伺服器獲取引數的幾種常見方式。
1)GET通過 request.args 獲取params值,沒有匹配的為None
from flask import request @app_product.route("/api/product/search",methods=['GET']) def product_search(): # 獲取?後指定的title值,沒有為None title = request.args.get('title') return {'tilte':title}
執行請求測試如下:
2)POST通過 requext.form 獲取form值,也可以用arg獲取所有引數和指定引數,具體解釋看程式碼註釋
from flask import request @app_product.route("/api/product/create",methods=['POST']) def product_create(): # 獲取?後指定title=的值,取不到預設為None title = request.args.get('title') # args 獲取所有URL?後邊的引數和值 args = request.args print(args) # 獲取Post format格式的值(缺失會報錯) keyCode = request.form["keyCode"] return {'title': title, 'keyCode': keyCode}
執行請求測試如下:
3)POST通過 request.get_data() 獲取json body引數,也通過request.json.get("key")獲取body內指定關鍵詞的值。
from flask import request @app_product.route("/api/product/update",methods=['POST']) def product_update(): # 獲取body中某個值,取不到預設為None keyCode = request.json.get('keyCodes') print(keyCode) # 獲取整個json字串體 body = request.get_data() print(type(body)) return body
執行請求測試如下:
這裡在擴充套件一個可能用到了傳參方式,路徑的引數形式,並可以嚴格限制傳遞的型別,方式在route path 定義<型別:關鍵詞>,然後通過方法同關鍵詞引數獲取。
@app.route('/api/project/remove/<int:project_id>',methods=['DELETE']) def project_remove(project_id): print(project_id) return '我是從路徑獲取並且只接收int型別:{}'.format(project_id)
進行delete方法請求測試結果如下
跨域問題
專案是一個前後端分離的程式,由於 瀏覽器同源策略 會產生跨域問題,解決的辦法是前端做路由轉發,或者後端服務開啟可跨域,之前在前後端互通的章節講過,這裡直接貼出程式碼。
flask_cors * app = Flask(__name__) CORS(app, supports_credentials=True)
至於什麼是同源策略,可以參考給出的參考文件自行擴充套件閱讀。
相信通過之前本篇總結,再加上之前幾個實戰分享,flask實現介面是不是如此簡單啦,下一篇將對vue前端進行一個小結。
【參考&擴充】
Flask中文文件:https://dormousehole.readthedocs.io/en/latest/index.html
Flask英文API文件:https://flask.palletsprojects.com/en/2.0.x/api/
瀏覽器同源策略:https://developer.mozilla.org/zh-CN/docs/Web/Security/Same-origin_policy
原創不易,經過實踐的總結分享更不易,如果你覺得有用,請點選推薦,也歡迎關注我部落格園和微信公眾號。