0 序言
Flask 是 Python 生態中一款輕量級 Web 框架,以簡潔、靈活著稱。
學習 Flask 的意義在于:
- 快速開發:通過少量代碼即可
搭建功能完整的 Web 應用
; - 理解原理:其設計清晰體現了 Web 框架的核心邏輯,如路由、請求處理、模板渲染等操作;
- 拓展性強:支持自定義擴展(如數據庫、認證),適配不同場景。
本筆記圍繞 Flask 核心功能
展開,結合代碼示例,逐步拆解 Web 開發的關鍵環節。
1 Flask 應用初始化
創建 Flask 應用實例,是所有功能的起點。
如果當前你的python環境里沒有flask這個包,就自行使用以下命令下載即可:
pip install flask
__name__
幫助 Flask 定位項目路徑(如模板、靜態文件的加載)。
運行以下程序:
from flask import Flask
app = Flask(__name__) # 初始化應用,__name__ 標識當前模塊 if __name__ == '__main__': app.run() # 啟動開發服務器,僅用于測試環境
注意事項:
app.run()
默認運行在127.0.0.1:5000
,生產環境需用 Gunicorn 等服務器;- 調試模式可通過
app.run(debug=True)
開啟,便于開發時自動重啟和報錯調試。
運行結果如下:
接著我們需要將http://127.0.0.1:5000 這個結果復制到網頁中打開。
當然,在VsCode中,你也可以直接ctrl+單擊
即可打開。
但是在這里,當我們打開相關鏈接時,我們會發現:
這里的原因主要是:前面程序里沒有定義任何路由(比如 /、/hello 等),所以訪問任何 URL 都會報 404。
由于Flask的路由是 “顯式定義” 的,只有通過 @app.route(…) 裝飾器聲明的 URL 路徑,才能被服務器識別和處理。
當你訪問http://127.0.0.1:5000/
時,Flask 會檢查是否有函數綁定了 / 這個路徑;
如果沒有找到匹配的路由,就會返回 404 Not Found(服務器不知道如何處理這個請求)。
接下來,第2小結就來重點解決這個問題!
2.路由系統:URL與視圖的映射
路由是 Web 應用的入口規則
:通過 @app.route
裝飾器,將 URL 路徑與 Python 函數綁定,處理客戶端請求。
2.1 基礎路由
定義最基本的 URL 映射,如首頁 /
、功能頁 /hello
。
- 示例:
from flask import Flask
app = Flask(__name__) # 定義路由
@app.route('/')
def index(): return 'Hello, World!' @app.route('/hello')
def hello(): return 'This is Hello Page' # 調試:打印所有注冊的路由
print("當前注冊的路由:")
print(app.url_map) # 關鍵!查看 Flask 到底注冊了哪些路由 if __name__ == '__main__': app.run(debug=True)
運行程序,看看結果:
接著我們打開網址:
看到這里,我們再來對剛剛的程序進行逐一分析,重點是要理解它的運行原理:
第一步:導入Flask類并創建應用實例(初始化階段)
from flask import Flask
app = Flask(__name__)
這一步創建了一個Flask應用實例,是整個Web應用的核心
__name__
參數的作用:
- 告訴Flask應用當前模塊的名稱
- 幫助Flask確定應用的根目錄,用于查找模板和靜態文件
- 當直接運行該腳本時,
__name__
的值為'__main__'
第二步:定義路由和視圖函數(路由注冊階段)
@app.route('/')
def index(): return 'Hello, World!'
這里包含兩個比較重要的部分,一個是路由裝飾器,另一個則是視圖函數。
路由裝飾器@app.route('/')
:
-
這是Flask的核心機制,使用Python裝飾器語法
-
作用是將URL路徑
'/'
與下面的視圖函數index()
綁定 -
當用戶訪問
http://127.0.0.1:5000/
時,Flask會調用index()
函數 -
視圖函數
index()
:- 處理對應路由的業務邏輯
- 返回值會作為HTTP響應的內容發送給客戶端
- 可以返回字符串、HTML、JSON等多種格式
第三步:打印路由信息(調試階段)
print("當前注冊的路由:")
print(app.url_map)
app.url_map
:- 是Flask內部維護的路由映射表
- 包含了所有已注冊的URL規則和對應的視圖函數
- 運行時會輸出所有可用的路由信息,方便調試
第四步:啟動開發服務器(運行階段)
if __name__ == '__main__': app.run(debug=True)
-
if __name__ == '__main__':
:- 確保只有當直接運行該腳本時才啟動服務器
- 當該腳本被作為模塊導入時,不會執行服務器啟動代碼!!!
-
app.run(debug=True)
:- 啟動Flask內置的開發服務器
debug=True
開啟調試模式,具有以下特性:- 代碼修改后自動重啟服務器
- 出現錯誤時顯示詳細的調試信息
- 僅用于開發環境,生產環境必須關閉
當用戶在瀏覽器中訪問http://127.0.0.1:5000/hello
時,整個處理流程如下:
- 瀏覽器向Flask服務器發送HTTP GET請求
- Flask服務器接收請求,解析URL路徑
/hello
- 在
app.url_map
中查找與/hello
匹配的路由規則 - 找到匹配的視圖函數
hello()
并調用 - 執行
hello()
函數,獲取返回值'This is Hello Page'
- Flask將返回值包裝成HTTP響應,發送給瀏覽器
- 瀏覽器接收響應并顯示內容
也就是說,這個簡單的程序實例展示了Web框架的核心思想:將URL路徑映射到處理函數,處理請求并返回響應。
2.2 請求方法與端點
methods
:限制請求方式(如僅允許GET
或POST
),保證接口安全;endpoint
:自定義路由的唯一標識
,避免視圖函數名沖突。
@app.route('/hi', methods=['GET', 'POST'], endpoint='hi_page')
def hi(): # 若 endpoint 不指定,默認用函數名 `hi` 作為標識 return 'Hi!'
運行程序后結果如下:
這個程序跟上一小節的程序顯示出來的結果都是一樣的,
區別主要在哪里呢?
多了兩個關鍵參數:methods
和 endpoint
methods=['GET', 'POST']
主要是用于限制允許的請求方式
- 默認情況:前面的
index()
、hello()
沒寫methods
,默認只允許GET
請求(瀏覽器地址欄訪問、點擊鏈接等都是GET
)。 - 這里的變化:
methods=['GET', 'POST']
表示這個路由既允許GET
請求,也允許POST
請求(如表單提交、API 數據提交等)。
打個比方:
- 用瀏覽器訪問
http://127.0.0.1:5000/hi
(GET
請求)→ 正常返回Hi!
; - 用表單或代碼向
http://127.0.0.1:5000/hi
提交數據(POST
請求)→ 也能正常處理(前面的路由會拒絕POST
請求)。
而這里的endpoint='hi_page'
則是自定義路由的唯一標識
- 默認情況:前面的
index()
、hello()
沒寫endpoint
,Flask會默認用函數名作為路由的唯一標識。 - 這里的變化:
endpoint='hi_page'
手動指定了標識,不再依賴函數名hi
。
作用:
- 避免函數名沖突:比如有兩個函數名相同但路徑不同的路由,可通過
endpoint
區分; - 方便 URL 反轉:用
url_for('hi_page')
可以生成該路由的 URL,而不是依賴函數名url_for('hi')
。
舉例:
from flask import url_for
# 生成 URL 時,用 endpoint 而不是函數名
print(url_for('hi_page')) # 輸出 '/hi'(不管函數名叫什么)
也可以看下表,可能會更清晰直觀。
特性 | 前面的 index() /hello() | 這里的 hi() |
---|---|---|
允許的請求方式 | 只允許 GET (默認) | 允許 GET 和 POST (顯式指定) |
路由的唯一標識(endpoint) | 等于函數名(如 index ) | 自定義為 hi_page (與函數名無關) |
3. 路由參數(轉換器)
前面定義的路由(如 /、/hello)都是靜態路徑,即每個 URL 對應固定的功能。但實際開發中,我們經常需要處理 動態變化的 URL:
舉個例子:
社交平臺的用戶主頁:/user/1(用戶 ID=1)、/user/2(用戶 ID=2);
電商平臺的商品詳情:/product/10086(商品 ID=10086);
博客的文章詳情:/post/20250730(文章日期 = 20250730)。
如果為每個用戶、商品、文章都單獨寫一個 @app.route,代碼會變得極其冗余,要是有10 萬個用戶就要寫 10 萬個路由。
這時候,路由參數(轉換器) 就能解決問題 —— 它允許我們在 URL 中定義 動態變量,讓同一路由規則匹配多個相似的URL
,并將動態部分作為參數傳遞給視圖函數。
接下來,我們就來學習 Flask 如何通過轉換器實現這種靈活的動態路由。
3.1 內置轉換器
Flask 提供默認轉換器:string
(默認,非斜杠字符串)、int
(整數)、float
(浮點數)、path
(含斜杠的路徑)。
@app.route('/user/<int:id>')
def user_detail(id): if id == 1: return 'Python' elif id == 2: return 'Django' return 'Hello'
我們對該程序進行分析,
程序核心是讓 URL 能夠包含動態變化的值并在視圖函數中處理這些值。
@app.route('/user/<int:id>') # 關鍵:<int:id> 是路由參數(帶轉換器)
def user_detail(id): # 函數參數 id 接收 URL 中的動態值# 處理邏輯...
<int:id>
:這是 Flask 的路由參數語法,由兩部分組成:
int
:轉換器,限制 URL 中的參數必須是整數(如果傳字符串,會直接報 404);id
:參數名,用于在視圖函數中接收這個動態值(必須和函數參數名一致)。
實際運行效果
當用戶訪問不同的 URL 時,id
會動態變化,視圖函數會根據 id
的值返回不同內容:
訪問的 URL | id 的值 | 函數返回內容 |
---|---|---|
http://127.0.0.1:5000/user/1 | 1 | Python |
http://127.0.0.1:5000/user/2 | 2 | Django |
http://127.0.0.1:5000/user/3 | 3 | Hello |
http://127.0.0.1:5000/user/abc | 無效(非整數) | 404 錯誤 |
接著我們來看看實際運行效果:
當然,除了這一種內置的轉換器外,還有一些其他的,不單單只是int類型,例如:
轉換器 | 作用 | 示例 URL | 匹配后的值類型 |
---|---|---|---|
string | 默認值,匹配非斜杠的字符串(不含 / ) | /user/<string:name> | 字符串 |
int | 匹配整數 | /user/<int:id> | 整數 |
float | 匹配浮點數 | /price/<float:p> | 浮點數 |
path | 匹配含斜杠的路徑(如文件路徑) | /file/<path:f> | 字符串 |
3.2 自定義正則轉換器
內置轉換器(int、string 等)就已經能滿足大部分簡單場景,但實際開發中,我們常需要更精確的參數規則。比如:
驗證手機號:必須是 11 位數字(int 只能保證是整數,無法限制長度為 11 位);
匹配日期:格式必須是 YYYY-MM-DD(string 無法驗證這種特定結構);
校驗郵箱:必須包含 @ 和域名(如 xxx@example.com)。
這些場景需要用正則表達式來定義精確規則,而內置轉換器無法直接支持自定義正則。
因此,我們就需要通過自定義正則轉換器,將正則規則與路由參數綁定,實現更靈活的參數校驗。
接下來,我們就來學習如何實現自定義正則轉換器,讓路由參數的驗證更靈活。
步驟:
① 繼承 BaseConverter
,定義 regex
屬性;
② 注冊到 app.url_map.converters
;
③ 在路由中使用自定義轉換器。
示例:
from flask import Flask
from werkzeug.routing import BaseConverter app = Flask(__name__) # 1. 定義自定義轉換器
class RegexConverter(BaseConverter): def __init__(self, url_map, regex): super().__init__(url_map) self.regex = regex # 正則規則由路由傳入 # 2. 注冊轉換器
app.url_map.converters['regex'] = RegexConverter # 3. 使用自定義轉換器
@app.route('/index/<regex("\d{3,6}"):value>')
def index(value): print(value) # 匹配 3-6 位數字 return 'OK'
這里逐一分析:
第一步:導入必要的類
from flask import Flask
from werkzeug.routing import BaseConverter # 導入轉換器基類
BaseConverter
是 Flask 路由轉換器的基類,所有自定義轉換器都必須繼承它。
第二步:定義自定義轉換器類
class RegexConverter(BaseConverter): def __init__(self, url_map, regex): super().__init__(url_map) # 調用父類初始化方法 self.regex = regex # 存儲正則規則(由路由傳入)
核心邏輯:通過 __init__
方法接收一個 regex
參數(正則表達式),并賦值給 self.regex
。
self.regex
是基類 BaseConverter
中用于匹配參數的關鍵屬性,Flask 會自動用這個正則規則驗證 URL 中的參數。
第三步:注冊轉換器到 Flask 應用
app.url_map.converters['regex'] = RegexConverter
將自定義的 RegexConverter
注冊到 Flask 的路由系統中,并給它起了一個別名 'regex'
。
后續在路由中,就可以用 <regex(正則規則):參數名>
的格式使用這個轉換器。
第四步:在路由中使用自定義轉換器
@app.route('/index/<regex("\d{3,6}"):value>')
def index(value): print(value) # 打印匹配到的參數(如 1234) return 'OK'
<regex("\d{3,6}"):value>
是使用格式:
regex
:我們注冊的轉換器別名;"\d{3,6}"
:傳給轉換器的正則規則(表示“3-6 位數字”);value
:參數名,用于在視圖函數中接收匹配到的值。
接下來運行一下,實際運行效果:
訪問不同的 URL 時,Flask 會用正則 \d{3,6}
驗證參數:
訪問的 URL | 是否匹配 | 視圖函數接收的 value | 頁面返回 |
---|---|---|---|
/index/123 | 匹配(3位數字) | '123' | OK |
/index/123456 | 匹配(6位數字) | '123456' | OK |
/index/12 | 不匹配(2位數字) | 無(直接返回 404) | 404 錯誤 |
/index/abc | 不匹配(非數字) | 無(直接返回 404) | 404 錯誤 |
4 模板渲染:分離邏輯與展示
前面的視圖函數都是通過 return 直接返回字符串(如 return ‘Hello, World!’),但實際的 Web 頁面往往包含大量 HTML、CSS、JavaScript 代碼(比如帶樣式的列表、表單、動態內容)。
如果繼續在 Python 代碼里硬寫 HTML,會出現很多問題,比如說:
維護困難:比如要修改頁面樣式(如字體顏色),需要在 Python 代碼中找對應的字符串修改,邏輯和展示混在一起;
可讀性差:復雜的 HTML 結構(如嵌套的 div、表格)寫在 Python 字符串里,格式混亂,容易出錯。
為了解決這些問題,我們可以用Flask引入模板渲染機制,即把頁面的 HTML 代碼放在專門的 templates 文件夾中,視圖函數只負責處理業務邏輯并傳遞數據,再通過模板引擎將數據動態插入 HTML 中。
接下來,我們就來學習如何使用 Flask 的模板渲染功能。
from flask import Flask, render_template app = Flask(__name__) @app.route('/index')
def index(): # 渲染 templates/index.html 文件 return render_template('index.html')
對程序進行分析,
第一步:導入模板渲染函數
from flask import Flask, render_template # 新增 render_template
render_template
是 Flask 提供的模板渲染函數,作用是:
- 找到并加載
templates
文件夾中的 HTML 文件; - 可以向 HTML 文件傳遞動態數據(后續擴展);
- 最終返回渲染后的完整 HTML 內容給瀏覽器。
第二步:定義路由與視圖函數
@app.route('/index')
def index(): # 渲染 templates/index.html 文件 return render_template('index.html')
- 當用戶訪問
http://127.0.0.1:5000/index
時,Flask 會執行index()
函數; render_template('index.html')
會自動到項目的templates
文件夾中尋找index.html
文件(必須提前創建這兩個)。
第三步:項目結構要求
使用模板渲染時,必須遵守 Flask 的默認目錄結構:
你的項目文件夾/
├── test.py (當前 Python 代碼文件)
└── templates/ (存放 HTML 模板的文件夾,必須叫這個名字) └── index.html (被渲染的 HTML 文件)
如果 templates
文件夾不存在,或 index.html
不在該文件夾中,會報 TemplateNotFound
錯誤。
我下面演示一下:
然后我們現在運行一下,
這里顯示空白的原因就是剛剛只是創建了一個html文件,該文件并沒有寫內容,所以是空白的。
接著我們在html文件里面寫進內容:
<!DOCTYPE html>
<html>
<head><title>測試頁面</title>
</head>
<body><h1>這是模板渲染的頁面!</h1><p>用戶您好,如果您能看到這句話,說明模板加載成功 ??</p>
</body>
</html>
這里簡單對程序分析一下:
<!DOCTYPE html> <!-- 1. 聲明文檔類型:HTML5 -->
<html> <!-- 2. 根元素:所有 HTML 內容的容器 -->
<head> <!-- 3. 頭部:存放元數據(不直接顯示,用于配置頁面) --><title>測試頁面</title> <!-- 頁面標題,顯示在瀏覽器標簽上 -->
</head>
<body> <!-- 4. 主體:存放頁面的可見內容 --><h1>這是模板渲染的頁面!</h1> <!-- 大標題,突出顯示 --><p>用戶您好,如果您能看到這句話,說明模板加載成功 ??</p> <!-- 段落文本,解釋信息 -->
</body>
</html>
重新運行下看看結果:
這里理解清楚后,后續我們就可以針對該網頁進行一些復雜的設計的時候,就可以先把它放到html文件里,然后在py文件調用就可以了。
程序的實際運行流程是這樣的:
- 用戶訪問
http://127.0.0.1:5000/index
; - Flask 匹配到
/index
路由,調用index()
函數; render_template('index.html')
執行:- 查找
templates/index.html
文件; - 讀取該文件的 HTML 內容;
- 將 HTML 內容作為響應返回給瀏覽器;
- 查找
- 瀏覽器解析 HTML 并顯示頁面。
相比于直接返回字符串,這種方法有以下3種優勢:
- 優勢1:HTML 結構更清晰:復雜的頁面布局(如 CSS 樣式、嵌套標簽)寫在
.html
文件中,比寫在 Python 字符串里更易讀、易修改; - 優勢2:前后端分離:在一些細分前后端開發的項目中,后端開發者只需關注
test.py
中的邏輯,前端開發者只需修改index.html
的樣式,分工更明確; - 優勢3:支持動態數據(后續擴展):可以在
render_template
中傳遞參數(如render_template('index.html', name='Python')
),在 HTML 中用{{ name }}
顯示,實現動態內容。
5 請求處理:request 對象
前面的模板渲染讓頁面能展示內容
,但 Web 應用的核心是**“和用戶互動”**:
比如:用戶在登錄頁提交賬號密碼、用戶在搜索框輸入關鍵詞、用戶上傳頭像或文件等等
這些場景都需要獲取用戶的輸入數據
,但如何把瀏覽器提交的數據傳遞到 Flask 代碼里?
這時候,request 對象 就成了核心工具。
接下來,我們通過一個登錄功能的示例,學習如何用 request 處理用戶的 GET/POST 請求,實現 頁面展示 + 數據交互
的完整流程。
from flask import Flask, render_template, request app = Flask(__name__) @app.route('/login', methods=['GET', 'POST'])
def login(): if request.method == 'GET': # 處理 GET 請求:渲染登錄頁面 return render_template('login.html') elif request.method == 'POST': # 處理 POST 請求:獲取表單數據 username = request.form.get('username') password = request.form.get('password') print(f'用戶名:{username},密碼:{password}') return '登錄成功!'
老樣子,先對程序進行分析:
這個程序實現了一個簡單的登錄功能:
- 當用戶通過 GET 請求 訪問
/login
時,顯示登錄頁面(login.html
); - 當用戶在登錄頁面提交表單(POST 請求)時,Flask 接收表單中的用戶名和密碼,并返回
登錄成功
。
第一步:導入核心工具
from flask import Flask, render_template, request # 新增 request 對象
request
是 Flask 中處理請求的核心對象,封裝了客戶端發送的所有數據(如請求方式、表單內容、URL 參數等)。
第二步:定義支持 GET/POST 的路由
@app.route('/login', methods=['GET', 'POST']) # 允許兩種請求方式
def login(): # 根據請求方式處理不同邏輯
methods=['GET', 'POST']
表示該路由同時支持 GET 和 POST 兩種請求方式:
- GET:通常用于“獲取資源”(如訪問頁面、查詢數據);
- POST:通常用于“提交數據”(如表單提交、上傳文件)。
(這個部分前面說過了,這里不再贅述)
第三步:處理 GET 請求:展示登錄頁面
if request.method == 'GET': # 處理 GET 請求:渲染登錄頁面 return render_template('login.html')
- 當用戶在瀏覽器地址欄輸入
http://127.0.0.1:5000/login
時,發送的是 GET 請求; request.method == 'GET'
條件成立,Flask 渲染templates/login.html
(登錄頁面),讓用戶可以輸入賬號密碼。
第四步:處理 POST 請求:接收表單數據
elif request.method == 'POST': # 處理 POST 請求:獲取表單數據 username = request.form.get('username') # 獲取表單中 name="username" 的值 password = request.form.get('password') # 獲取表單中 name="password" 的值 print(f'用戶名:{username},密碼:{password}') # 在終端打印數據 return '登錄成功!'
- 當用戶在登錄頁面點擊“提交”按鈕時,表單會以 POST 請求 提交到
/login
; request.method == 'POST'
條件成立,通過request.form.get('字段名')
提取表單數據:- 假設
login.html
中有<input name="username">
,則request.form.get('username')
會獲取用戶輸入的用戶名; - 同理,
request.form.get('password')
獲取密碼。
- 假設
要讓這個程序正常運行,templates
文件夾中需要有 login.html
(登錄表單頁面),內容大致如下:
<!DOCTYPE html>
<html>
<body><form method="POST"> <!-- 表單提交方式為 POST --><label>用戶名:</label><input type="text" name="username"><br> <!-- name 必須為 "username" --><label>密碼:</label><input type="password" name="password"><br> <!-- name 必須為 "password" --><button type="submit">登錄</button></form>
</body>
</html>
- 表單的
method="POST"
必須與 Flask 路由允許的方式一致; - 輸入框的
name
屬性(username
、password
)必須與request.form.get('xxx')
中的參數一致,否則無法獲取數據。
完整交互流程如下:
- 用戶訪問
http://127.0.0.1:5000/login
(GET 請求)→ Flask 返回登錄頁面; - 用戶在頁面輸入用戶名和密碼,點擊“登錄”→ 表單以 POST 請求 提交到
/login
; - Flask 檢測到 POST 請求,通過
request.form
獲取表單數據 → 終端打印用戶名和密碼; - Flask 返回
登錄成功!
→ 瀏覽器顯示成功信息。
運行下程序,結果如下:
通過這一小節,我們也能明白request
對象的核心作用,
request
是連接用戶輸入
和后端邏輯
的橋梁,除了 form
(表單數據),還常用這些屬性:
request.args
:獲取 URL 中的查詢參數(如?page=1&size=10
);request.files
:獲取上傳的文件(如頭像圖片);request.headers
:獲取請求頭信息(如瀏覽器類型、Cookie)。
這是 Web 應用中用戶交互
的基礎模式,無論是登錄、注冊還是表單提交,都遵循類似的邏輯。
6 重定向與 URL 構建
在完成用戶交互(如表單提交)后,我們常常需要 “引導用戶前往新頁面”:
例如:用戶登錄成功后,從登錄頁跳轉到首頁;用戶注冊成功后,從注冊頁跳轉到個人中心;
用戶訪問了不存在的頁面時,自動跳轉到 404 提示頁。
這種頁面跳轉
的需求,就需要用重定向(redirect) 來實現。
同時,在跳轉或頁面鏈接中,我們不可避免要寫 URL。但如果直接硬編碼 URL,會帶來一個問題:一旦路由規則修改(比如 /home 改成 /index),所有用到這個 URL 的地方都要手動修改,非常繁瑣。
為了解決這個問題,Flask 提供了 url_for 函數,它能通過視圖函數名
動態生成對應的 URL
也就是路由修改時,生成的 URL 會自動更新。
接下來,我們就來學習如何用 redirect 實現頁面跳轉,以及如何用 url_for 動態構建 URL,讓程序更靈活、易維護。
from flask import Flask, redirect, url_for app = Flask(__name__) @app.route('/index')
def index(): # 重定向到 hello 視圖(通過 url_for 生成 URL) return redirect(url_for('hello')) @app.route('/hello')
def hello(): return 'Welcome to Hello Page!'
結果如下:
頁面下面也會顯示hello視圖函數的輸出內容。
7 總結
Flask 的核心設計圍繞簡潔靈活展開:
- 路由是請求的入口,支持動態參數和自定義規則;
- request 統一處理輸入,適配不同請求方式;
- 模板分離展示邏輯,提升可維護性;
- 重定向與 url_for 實現頁面跳轉和 URL 解耦。
學習 Flask 的過程,是逐步理解 Web 應用請求-處理-響應
流程的過程。
后續可結合數據庫、等擴展,搭建更復雜的項目(如博客、API 服務)。
建議多實踐,剩下的內容會在下文介紹,從簡單頁面到完整功能,逐步深化對 Web 開發的理解。