我們都知道 flask 是一個輕量級的 web 框架,相對於其他同類型框架更為靈活、輕便、安全且容易上手。開發者可以隨意編寫自己想要的專案結構,同時還有很多的第三方庫供君選擇。但是靈活的同時也帶來了相應的問題,比如對很多初學者來說,建的專案結構混亂,不易維護,還有經典的迴圈匯入等問題
迴圈匯入問題
很多初學者喜歡將啟動檔案和多個路由寫在同一個檔案中,例如以下程式碼:
這樣一旦隨著檢視函式的增多,程式碼的可維護性會變得越來越差。所以有必要對檢視函式進行拆分。
我們將其拆分成兩個檔案:run.py 和 view.py,其中 run.py 作為程式的啟動檔案,因為要將路由註冊到 flask 核心物件上,所以在 view.py 中需要匯入核心物件,同時 run.py 中要匯入 view。最終,程式碼和專案結構如下所示:
run.py
1# coding: utf-8 2__author__ = 'Jerry' 3 4from flask import Flask 5 6app = Flask(__name__) 7 8from app.web import view [email protected]("/")12def index():13 return 'Hello World'141516if __name__ == '__main__':17 app.run()view.py
1# coding: utf-8 2__author__ = 'Jerry' 3from flask import request 4 5from run import app 6 [email protected]("/add") 8def add(): 9 name = request.args.get("name")10 return f"Add {name}"[email protected]("/delete")13def delete():14 name = request.args.get("name")15 return f"Delete {name}"[email protected]("/change",methods=["POST"])18def change():19 num = request.json20 return f"change {num}"但是當我啟動程式,在瀏覽器中輸入地址 http://127.0.0.1:5000/add?name=Jerry 之後,報 404 Not Found。
404
而 127.0.0.1:5000/ 卻能正常響應!
200
這是為什麼呢? 為什麼在 view.py 中註冊的檢視函式找不到呢? 原因就是因為迴圈匯入,我們在 run.py 中匯入了 view, 同時又在 view.py 中匯入了 run.py 中的 app!最終導致什麼結果呢,我們通過除錯來發現吧!
詳解迴圈匯入
啟動 run, 第一次例項化一個 Flask 的核心物件 app,執行到匯入 view 程式碼,這是第一個關鍵點 1!由於,本次執行 _ name _ != _ main _,所以並不會執行 app.run()。那麼程式將繼續執行 view.py 中剩餘程式碼
可以看到,程式將相關的路由函式註冊到了 app2 上面!
當 view.py 中程式碼執行完成之後,將繼續執行 run.py 中後面的程式碼。也就是前面提到的關鍵點 1 之後的相關程式碼!
此時將路由函式 index 註冊到了 app 上面,同時 _ name _ == _ main _,所以 app.run() 啟動成功!
通過上面的分析,總結如下:
整個過程初始化了兩次 Flask 核心物件,app 和 app2view 中的檢視函式註冊在 app2 上面index 檢視函式註冊了兩次,第一次註冊到 app2,最後一次註冊 app 上面最終啟動的核心物件是 app現在你應該明白了,view.py 中的檢視函式註冊的 app 和最終啟動的 app 不是同一個,所以最終導致找不到檢視函式!為了能有個更直觀的感受,我們可以將 app 的記憶體地址打印出來,這樣更加一目了然!
可以看到,註冊和啟動的 app 不是同一個!
藍圖
解決方案:Flask 給我們提供一種機制,藍圖(Blueprint)。
藍圖就是一個儲存操作路由對映方法的容器,主要用來實現客戶端請求和 URL 相互關聯的功能。藍圖類似 Django 中的 app,兩者的功能非常相似,幫助我們實現模組化應用的功能。
在 Flask 中可以建立多個藍圖,代表不同的功能模組。比如,上面程式碼中的 web 資料夾就能作為一個藍圖,另外使用者相關的功能模組 user 也能建立一個相應的藍圖
藍圖應用
了解藍圖的相關功能之後,我們正式通過藍圖來解決以上問題。
首先在web/_ init _.py 檔案中建立藍圖: 1# coding: utf-8 2__author__ = 'Jerry' 3from flask import Blueprint 4 5api = Blueprint('api', __name__) 6 7from app.web import view 8 9if __name__ == '__main__':10 pass藍圖建立完之後,在 view.py 中匯入對應的藍圖,並將檢視函式註冊到藍圖中,改造完之後如下: 1# coding: utf-8 2__author__ = 'Jerry' 3from flask import request 4 5from . import api 6 7print(f"註冊view中的app: {id(api)}")00000 8 [email protected]("/add")10def add():11 name = request.args.get("name")12 return f"Add {name}"[email protected]("/delete")15def delete():16 name = request.args.get("name")17 return f"Delete {name}"[email protected]("/change", methods=["POST"])20def change():21 num = request.json22 return f"change {num}"我們自始至終都要清楚,Flask 中的相關功能外掛以及檢視函式最終都要註冊到核心物件上面,所以藍圖也是要註冊到核心物件上面。同時要了解到,當專案功能較多,用的外掛也很多的時候,核心物件的初始化以及藍圖、第三方外掛的註冊的相關程式碼會很多,這時候也要對程式碼進行分離。所以在 app/_ init _.py 檔案中做核心物件的初始化,同時將藍圖註冊到核心物件上。程式碼如下:
同時在啟動檔案 run.py 記得匯入 app 核心物件,修改後程式碼如下:
run.py
再次啟動,我們可以看到,因為一個是藍圖,一個是 app 兩者是不一致的。
驗證結果
執行之後,我們在瀏覽器中或者用程式碼來驗證一下:
GET 請求
POST 請求
完美!