Learning Objectives
- 說明 Flask 是什麼,以及 WSGI、Werkzeug、Jinja2 各自的角色
- 用 venv 建立虛擬環境、安裝 Flask,並在自己的電腦上啟動網站
- 說明 Flask(__name__)、路由與 view 函數的關係
- 說明除錯模式的 reloader 與 debugger,以及為什麼不能用在正式環境
Flask 是什麼
上一課操作的網站就是用 Flask 寫的。Flask 是 Python 的網頁框架,負責處理 HTTP 的細節,讓你只要寫「這個網址要回什麼」。
它被稱為微框架(microframework):核心很小,資料庫、表單驗證這些都不內建,需要時再選用擴充套件或自己寫。這一軌會直接用 Python 內建的 sqlite3 接資料庫,也比較看得清楚每一步在做什麼。
幾個會反覆看到的名字:
| 名稱 | 是什麼 |
|---|---|
| WSGI | Python 網頁應用程式與伺服器之間的標準介面。Flask 程式就是一個 WSGI 應用程式 |
| Werkzeug | 實作 WSGI 的工具組:解析請求、比對路由、開發用伺服器 |
| Jinja2 | 模板語言,用來產生 HTML(第 6 課) |
| MarkupSafe | 跳脫 HTML 特殊字元,防止注入 |
| ItsDangerous | 替資料簽章,用來保護 Session Cookie(第 14 課) |
安裝 Flask 時,這些套件會一起裝好。
在自己的電腦上跑起來
下面的輸出是在 Windows 11、Python 3.12 上實際執行的結果。版本號依你安裝的時間而定,看到較新的版本是正常的。如果手邊沒有電腦可以操作,先往下看,課程裡的範例都能直接在瀏覽器執行。
-
1
建立專案資料夾與虛擬環境
虛擬環境(virtual environment)是每個專案自己的一組套件,不會和其他專案打架,這是 Python 內建的
venv模組提供的功能。下面是 Windows。macOS 與 Linux 的最後一行改成
python3 -m venv .venv。PowerShell 的mkdir會多印一段新資料夾的資訊,這裡省略。 -
2
啟用虛擬環境
每次開新的終端機都要啟用一次。啟用後,命令列前面會出現
(.venv)。系統與終端機 指令 Windows PowerShell .venv\Scripts\Activate.ps1Windows 命令提示字元 .venv\Scripts\activate.batmacOS、Linux source .venv/bin/activatePowerShell 如果說不允許執行指令碼,先執行
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser(Python 官方文件的建議)。要離開虛擬環境時輸入deactivate。 -
3
安裝 Flask
pip install的下載過程省略,只留最後一行。pip freeze列出目前環境裝了哪些套件和版本,第 19 課部署時會用它產生requirements.txt。 -
4
寫 app.py
在
myproject資料夾新增app.py。不要取名叫flask.py,會和 Flask 本身衝突。from flask import Flask app = Flask(__name__) @app.route('/') def index(): return 'Hello, Flask!' if __name__ == '__main__': app.run(debug=True) -
5
啟動開發伺服器
--app app指定程式在app.py,--debug打開除錯模式。伺服器會一直等待請求,所以命令列不會回來。用瀏覽器開
http://127.0.0.1:5000/就看到 Hello, Flask!,每個請求都會印一行紀錄(下面最後兩行是開了/和不存在的/nothing)。PIN 碼每台電腦不同。按 Ctrl+C 停止伺服器。127.0.0.1是你自己的電腦,別人連不到。如果出現
OSError,代表 5000 埠已經有別的程式在用,可以改用flask --app app run --debug --port 5001。macOS 的「AirPlay 接收器」常佔用 5000。 -
6
另一種啟動方式:python app.py
python app.py會執行檔案最下面的app.run(debug=True),輸出幾乎相同。官方文件建議用flask run,因為app.run()的伺服器在重新載入時,遇到錯誤會直接結束。app.run()一定要放在if __name__ == '__main__':裡面,否則日後用正式伺服器匯入這個檔案時會干擾。
逐步看:網址怎麼走到函數
瀏覽器的環境不能開真的伺服器,所以課程裡的範例用 client = app.test_client() 當作瀏覽器:client.get('/') 等於瀏覽器請求 /,回傳值就是回應。Flask 本身是真的,只是請求不經過網路。
注意呼叫堆疊:client.get 之後會直接跳進 index,中間 Flask 做的事不顯示。
路由、view 函數與 __name__
- 路由(route):網址與處理函數的對應關係。
- view 函數:處理某個網址的函數,它的回傳值會變成回應。
- 端點(endpoint):路由的內部名稱,預設就是函數名稱,第 3 課的
url_for會用到。
@app.route('/') 只是登記的簡寫。Flask 另外提供 app.add_url_rule(網址, 端點, 函數),做的事情完全一樣,平常用裝飾器就好,看到別人這樣寫時要認得。
__name__ 是 Python 自動設定的變數:直接執行檔案時是 '__main__',被別的程式匯入時是模組名稱。
逐步看:路由表裡有什麼
app.url_map 就是 Flask 的路由表。看看兩種登記方式的結果,以及表裡多出來的一筆。
除錯模式
--debug 或 debug=True 會打開兩個功能:
| 功能 | 做什麼 |
|---|---|
| reloader | 監看原始碼,檔案一改就自動重新啟動伺服器 |
| debugger | 發生未處理的錯誤時,瀏覽器顯示互動式的錯誤頁面,可以看堆疊,甚至執行 Python |
開發時很方便,但是 除錯模式與開發伺服器都不可以用在正式環境。debugger 允許從瀏覽器執行任意 Python 程式,雖然有 PIN 碼保護,仍然是很大的安全風險;開發伺服器也沒有為效率、穩定與安全設計。正式環境怎麼做是第 19 課的內容。
開啟除錯模式時,程式發生錯誤會顯示 debugger;關閉時,使用者只看到簡單的 500 Internal Server Error,詳細的錯誤寫在伺服器紀錄。下面的練習是後者。
動手做:讀書會網站的兩個頁面
用兩種方式各登記一個路由:/ 用裝飾器,/schedule 用 add_url_rule。程式最下面的測試不要改。
想一想
Flask 為什麼被稱為微框架?
下面的程式會印出什麼?
from flask import Flask
app = Flask(__name__)
@app.route('/hi')
def hi():
return 'hi'
client = app.test_client()
print(client.get('/hi').status_code, client.get('/').status_code)
為什麼不可以在正式環境開除錯模式?
虛擬環境解決什麼問題?
關於 @app.route('/'),下面哪個說法正確?
重點整理
- 每個專案一個虛擬環境:
python -m venv .venv、啟用、pip install flask - 啟動:
flask --app app run --debug;app.run()要放在if __name__ == '__main__':裡 - 路由把網址對應到 view 函數,view 函數的回傳值變成回應
Flask(__name__)讓 Flask 找得到模板與靜態檔案- 除錯模式的 reloader 和 debugger 只能在開發時使用
- 課程範例用
app.test_client()當瀏覽器;在自己的電腦上可以用真的瀏覽器
下一課讓網址可以帶變數,例如 /note/3,並處理不同的 HTTP 方法。