在 Visual Studio Code 中進行 FastAPI 教學
FastAPI 是一個現代化且高效能的 Web 框架,用於使用 Python 建立 API。它的設計旨在讓開發者能夠快速且高效地建構 API,同時提供自動驗證、序列化和 API 文件化等功能,使其成為開發 Web 服務和微服務的熱門選擇。
在本 FastAPI 教學中,我們將使用 FastAPI 建立一個購物清單應用程式。學完本教學後,您將了解如何在 Visual Studio Code 的終端機、編輯器和偵錯器中使用 FastAPI。本教學並非深入探討 FastAPI 的內容。如需深入了解,您可以參考 FastAPI 官方文件。
如果您是第一次使用 Python,建議您從我們的 Python 教學開始,以熟悉該語言以及 VS Code 對 Python 的支援。本教學更適合那些已經熟悉 Python 並希望學習如何在 VS Code 中使用 FastAPI 的開發者。
本 FastAPI 教學的完整專案程式碼可在 GitHub 上找到:python-sample-vscode-fastapi-tutorial。
如果您遇到任何問題,可以在 Python 擴充功能討論問答 (Discussions Q&A) 中搜尋解答或提問。
設定專案
您可以透過不同的方式設定本教學的專案。我們將涵蓋如何在 GitHub Codespaces 以及 您本機的 VS Code 中進行設定。
GitHub Codespaces
您可以將此專案設定為在 GitHub Codespaces 中開發,這樣您就可以在 codespace 中遠端進行編碼、偵錯和執行應用程式。Codespace 提供了一個託管在雲端的全配置開發環境,無需進行本機設定。此環境包含專案的依賴項、工具和延伸模組,確保了開發體驗的一致性和可重複性。它透過提供即時編輯、整合版本控制以及方便存取偵錯和測試工具,簡化了協作流程,同時維護了專案的安全性和可靠性。
注意:所有 GitHub.com 帳戶在 Free 或 Pro 方案中都包含每月免費使用 GitHub Codespaces 的額度。如需更多資訊,請前往 關於 GitHub Codespaces 的計費。
若要為本教學設定 codespace,請前往此專案的 GitHub 儲存庫。此 codespace 包含快速開始 FastAPI 開發所需的所有設定和依賴項。
對於本教學,請選擇 dictionarybased 分支。

然後,選擇 Code > Codespaces > Create Codespace on <dictionarybased> 分支,以建立並開啟專案的 codespace。
完成後,您可以繼續閱讀下方的替換資料庫章節。
本機 VS Code 設定
若要順利完成本教學,您首先需要在 VS Code 中設定您的 Python 開發環境。具體來說,本教學需要:
- Python 3(如果您尚未安裝,請查看安裝指南)
- VS Code 的 Python 延伸模組(關於安裝延伸模組的更多詳細資料,您可以閱讀延伸模組市場)。
在本章節中,我們將建立一個資料夾作為 VS Code 中的工作區,設定 Python 虛擬環境,並安裝專案的依賴項。
-
在您的檔案系統中,為本教學建立一個專案資料夾,例如
groceries-plugin。 -
在 VS Code 中開啟此新資料夾(檔案 > 開啟資料夾...)。
-
當出現工作區信任 (Workspace Trust) 提示時,請選擇 是的,我信任作者,以允許工作區存取必要的資源和延伸模組。您可以在說明文件中了解更多關於工作區信任的資訊。
現在,讓我們建立一個 requirements.txt 檔案,列出我們希望為應用程式安裝的依賴項。requirements.txt 檔案是 Python 開發中的常見做法,用於指定專案所依賴的程式庫及其版本。此檔案有助於確保任何參與專案的人員都能重建類似的開發環境,使其成為維護一致性的便利元件。
我們將安裝用於建立應用程式的 FastAPI、作為伺服器的 uvicorn,以及用於處理資料儲存和與 Redis 資料庫互動的 Redis 和 type-redis。
-
在 VS Code 中建立一個新檔案(檔案 > 新增文字檔 或 ⌘N (Windows, Linux Ctrl+N))。
-
將以下內容加入其中。
fastapi redis types-redis uvicorn -
儲存檔案(⌘S (Windows, Linux Ctrl+S))並將其命名為
requirements.txt。 -
透過開啟指令選擇區 (Command Palette)(⇧⌘P (Windows, Linux Ctrl+Shift+P))並執行 Python: Create Environment 指令來建立虛擬環境。
注意:此步驟可能需要幾分鐘才能完成。
-
當詢問環境類型時,請選擇 Venv。

-
然後選擇您機器上可用的最新版 Python。

-
從下拉式清單中選擇
requirements.txt檔案,以便自動安裝依賴項,然後選擇 確定。
虛擬環境將會建立,依賴項會自動安裝,並且該環境會被選定為您工作區所使用的 Python 延伸模組環境。您可以透過檢查 VS Code 的右下角來確認它是否已選定。

注意:如果您在狀態列上找不到剛建立的環境資訊,可以點選 Python 解譯器指示器(或從指令選擇區執行 Python: Select Interpreter 指令)並手動選擇該虛擬環境。
開始編碼
讓我們開始建立應用程式!
-
使用 檔案 > 新增檔案... 建立一個新的 Python 檔案,然後選擇 Python File。
-
將其儲存為
main.py(⇧⌘S (Windows, Linux Ctrl+Shift+S))並放在groceries-plugin資料夾中。 -
將以下程式碼加入
main.py並儲存檔案。from fastapi import FastAPI app = FastAPI() @app.get("/") def root(): return {"message": "Hello World"} -
透過啟動偵錯器(F5)來執行程式碼。
-
從下拉式選單中,從清單中選擇 FastAPI 設定選項。

這會自動建立一個偵錯設定,該設定會呼叫 uvicorn 透過偵錯器啟動應用程式伺服器,並允許您逐步執行原始程式碼以檢查其行為。您應該會在終端機中看到類似以下的內容:

提示:如果您的預設連接埠已被佔用,請停止偵錯器並開啟指令選擇區(⇧⌘P (Windows, Linux Ctrl+Shift+P)),搜尋 Debug: Add Configuration,選擇 Python Debugger,然後選擇 FastAPI。這將在
.vscode/launch.json中建立一個您可以編輯的自訂設定檔。在"args":[]中加入以下內容來設定自訂連接埠:"--port=5000"。儲存檔案,然後再次使用(F5)啟動偵錯器。 -
Ctrl+點選 終端機中的
http://127.0.0.1:8000/URL,以開啟預設瀏覽器並導向至該位址。
恭喜!您的 FastAPI 應用程式已成功執行!
-
使用偵錯工具列中的 停止 按鈕,或透過 ⇧F5 (Windows, Linux Shift+F5) 來停止偵錯器。
為購物清單項目建立模型
現在我們已經讓 FastAPI 應用程式正常運作,我們可以使用 Pydantic 來定義我們的購物清單項目。Pydantic 是一個與 FastAPI 無縫整合的資料驗證和解析程式庫。Pydantic 允許您使用帶有 型別提示 (type hints) 的 Python 類別來定義資料模型,以便對 API 請求中的傳入資料(稱為「酬載」(payloads))進行自動驗證和解析。
讓我們為購物清單項目建立一個模型。我們將使用 ItemPayload 模型來定義要加入購物清單的項目資料結構。此模型將包含三個欄位:item_id、item_name 和 quantity。
-
使用 檔案 > 新增檔案... 建立一個新的 Python 檔案,然後選擇 Python File。
-
將以下幾行加入檔案,然後將其儲存為
models.py(⇧⌘S (Windows, Linux Ctrl+Shift+S))並放在groceries-plugin資料夾中。from typing import Optional from pydantic import BaseModel class ItemPayload(BaseModel): item_id: Optional[int] item_name: str quantity: int
Pylance 是 VS Code 中預設的 Python 語言伺服器,它支援對於處理 Pydantic 模型和 FastAPI 非常有用的型別提示功能。這是因為 Pylance 建立在 Pyright 之上,Pyright 是一個 Python 靜態型別檢查器,可以偵測程式碼中的型別錯誤,從而防止錯誤並提高程式碼品質。
以下三個步驟是選用的,但考慮到 FastAPI 大量使用型別提示來改善程式碼的可讀性和驗證,我們可以利用 Pylance 的型別檢查功能儘早發現錯誤。
-
開啟設定編輯器(⌘, (Windows, Linux Ctrl+,))。
-
搜尋 "python type checking mode" 並將其設定為
basic以進行基礎的型別檢查。Pylance 現在會顯示診斷資訊和警告,以抓取簡單的型別相關錯誤。或者,您可以將其設定為strict以執行更進階的 型別檢查規則。
-
接著,搜尋 "Python inlay type hints",並啟用 Variable Types 和 Function Return Types 的鑲嵌提示 (inlay hints)。

建立路由
現在我們需要一個地方來儲存購物清單項目。為了簡單起見,讓我們從一個空字典開始。
-
首先,讓我們匯入範例所需的所有套件。開啟
main.py檔案,並將第一行匯入程式碼取代為以下內容。from fastapi import FastAPI, HTTPException from models import ItemPayload -
現在在
app = FastAPI()下方加入以下程式碼。grocery_list: dict[int, ItemPayload] = {}這建立了一個新的空字典,用於接收
int類型的鍵(作為項目 ID)和ItemPayload類型的值。我們現在將在 FastAPI 應用程式中定義路由。在 Web 應用程式的語境中,路由就像是將特定 URL 對應到處理它們的程式碼的路徑。這些路由作為我們應用程式中不同功能的進入點。當客戶端(如網頁瀏覽器或其他程式)向我們的應用程式傳送包含特定 URL 的請求時,FastAPI 會根據該 URL 將請求路由至適當的函式(也稱為路由處理常式或視圖函式),然後該函式會處理請求並產生回應。
讓我們繼續定義用於新增和擷取個別項目,以及傳回購物清單中所有項目的路由。
-
在
main.py檔案的結尾加入以下路由。# Route to add an item @app.post("/items/{item_name}/{quantity}") def add_item(item_name: str, quantity: int): if quantity <= 0: raise HTTPException(status_code=400, detail="Quantity must be greater than 0.") # if item already exists, we'll just add the quantity. # get all item names items_ids = {item.item_name: item.item_id if item.item_id is not None else 0 for item in grocery_list.values()} if item_name in items_ids.keys(): # get index of item_name in item_ids, which is the item_id item_id = items_ids[item_name] grocery_list[item_id].quantity += quantity # otherwise, create a new item else: # generate an ID for the item based on the highest ID in the grocery_list item_id = max(grocery_list.keys()) + 1 if grocery_list else 0 grocery_list[item_id] = ItemPayload( item_id=item_id, item_name=item_name, quantity=quantity ) return {"item": grocery_list[item_id]}如果您已在上一個章節啟用型別提示,您可能會注意到 Pylance 加入了帶有函式回傳型別,以及
item_ids和item_id型別的鑲嵌提示。您可以選擇按兩下每個建議將其插入程式碼中。
現在讓我們檢查此路由是否如預期運作。最快的方法是同時使用 VS Code 的偵錯器以及 FastAPI 的
/docs端點,該端點提供有關所有可用 API 路由的資訊,並讓您與 API 互動以探索其參數和回應。此文件是根據 FastAPI 應用程式中定義的中繼資料和型別提示動態產生的。 -
在
if quantity <= 0陳述式旁邊設定一個中斷點,點選行號左側的邊緣(或按下 F9)。偵錯器將會在該行執行前停止,以便您逐行檢查程式碼。
-
啟動偵錯器(F5),然後在瀏覽器中導向至
http://127.0.0.1:8000/docs。應該會出現一個 Swagger 介面,其中包含應用程式中可用的兩個端點:
/items和根目錄 (/)。
-
選擇
/items路由旁邊的向下箭頭將其展開,然後點選出現在右側的 Try it out 按鈕。
-
透過在
item_name欄位中傳入一個字串,並在quantity欄位中傳入一個數字來新增一個購物清單項目。例如,您可以將item_name設為 apple,將quantity設為 2。 -
選擇 Execute。

-
再次開啟 VS Code,並注意偵錯器已停在您稍早設定的中斷點處。

在左側的「變數」視窗中,顯示了此時定義的所有區域和全域變數,位於 執行與偵錯 檢視下。在我們的範例中,在區域變數檢視下,
item_name被設為 'apple',quantity被設為 2,並且在全域變數檢視下有一個空的grocery_list字典。
現在讓我們使用 VS Code 的「偵錯主控台」(Debug Console) 進行一些探索。
-
選取
quantity <= 0陳述式,在編輯器上按右鍵並選擇 在偵錯主控台中評估 (Evaluate in Debug Console)。
這會開啟「偵錯主控台」並執行選取的運算式。如我們範例中的預期,該運算式評估結果為
False。「偵錯主控台」是一個強大的工具,可以快速測試運算式,並在停在中斷點時更深入了解程式碼的狀態。您也可以使用它來執行任意程式碼,例如呼叫函式或列印變數。您可以在 Python 教學中進一步了解 VS Code 中的 Python 偵錯。
您現在可以透過選擇偵錯檢視工具列中的 繼續 (Continue),或按下 F5 來繼續執行程式碼。
最後,讓我們為應用程式加入剩餘的路由,這樣我們就可以列出所有項目或特定項目,以及從我們的購物清單中移除它們。您可以讓偵錯器保持執行狀態,因為當您儲存下個步驟中所做的變更時,它會自動重新載入應用程式。
-
將
main.py中的內容取代為下方的程式碼。from fastapi import FastAPI, HTTPException from models import ItemPayload app = FastAPI() grocery_list: dict[int, ItemPayload] = {} # Route to add an item @app.post("/items/{item_name}/{quantity}") def add_item(item_name: str, quantity: int) -> dict[str, ItemPayload]: if quantity <= 0: raise HTTPException(status_code=400, detail="Quantity must be greater than 0.") # if item already exists, we'll just add the quantity. # get all item names items_ids: dict[str, int] = { item.item_name: item.item_id if item.item_id is not None else 0 for item in grocery_list.values() } if item_name in items_ids.keys(): # get index of item_name in item_ids, which is the item_id item_id: int = items_ids[item_name] grocery_list[item_id].quantity += quantity # otherwise, create a new item else: # generate an ID for the item based on the highest ID in the grocery_list item_id: int = max(grocery_list.keys()) + 1 if grocery_list else 0 grocery_list[item_id] = ItemPayload( item_id=item_id, item_name=item_name, quantity=quantity ) return {"item": grocery_list[item_id]} # Route to list a specific item by ID @app.get("/items/{item_id}") def list_item(item_id: int) -> dict[str, ItemPayload]: if item_id not in grocery_list: raise HTTPException(status_code=404, detail="Item not found.") return {"item": grocery_list[item_id]} # Route to list all items @app.get("/items") def list_items() -> dict[str, dict[int, ItemPayload]]: return {"items": grocery_list} # Route to delete a specific item by ID @app.delete("/items/{item_id}") def delete_item(item_id: int) -> dict[str, str]: if item_id not in grocery_list: raise HTTPException(status_code=404, detail="Item not found.") del grocery_list[item_id] return {"result": "Item deleted."} # Route to remove some quantity of a specific item by ID @app.delete("/items/{item_id}/{quantity}") def remove_quantity(item_id: int, quantity: int) -> dict[str, str]: if item_id not in grocery_list: raise HTTPException(status_code=404, detail="Item not found.") # if quantity to be removed is higher or equal to item's quantity, delete the item if grocery_list[item_id].quantity <= quantity: del grocery_list[item_id] return {"result": "Item deleted."} else: grocery_list[item_id].quantity -= quantity return {"result": f"{quantity} items removed."} -
儲存檔案(⌘S (Windows, Linux Ctrl+S))。應用程式應該會自動重新載入。
您現在可以再次開啟 /docs 頁面並測試新路由,使用偵錯器和偵錯主控台來更了解程式碼的執行。完成後,您可以停止偵錯器(⇧F5 (Windows, Linux Shift+F5))。您也可以點選我們在第 4 步加入的中斷點將其移除。
恭喜!您現在擁有一個運作中的 FastAPI 應用程式,且具備新增、列出和刪除購物清單項目的路由。
設定資料儲存
此時,您已經擁有一個具備基本功能的應用程式。本章節將引導您設定用於持久化的資料儲存,但如果您對目前所學感到滿意,可以選擇跳過此章節。
到目前為止,我們將資料儲存在字典中,這並不理想,因為當應用程式重新啟動時,所有資料都會遺失。
為了持久化資料,我們將使用 Redis,這是一個開源的記憶體內資料結構儲存庫。由於其速度和多功能性,Redis 常被用作各種應用程式中的資料儲存系統,包括 Web 應用程式、即時分析系統、快取層、本教學等等。
如果您已經在使用我們現有範本的 GitHub Codespaces 上工作,您可以直接跳至替換資料庫章節。
如果您在 Windows 上,您可以透過設定 Docker 容器或 GitHub Codespace 來使用 Redis。在本教學中,我們將使用 Docker 容器,但您可以參考上方的章節以取得關於如何設定 GitHub Codespace 的說明。
否則,如果您是在 Linux 或 macOS 機器上,您可以依照其網站上的說明安裝 Redis,然後跳至替換資料庫章節。
在 Windows 上設定 Docker 容器
VS Code 的 Dev Containers 延伸模組提供了一種精簡的方法,將您的專案、依賴項和所有必要的工具整合到一個整潔的容器中,從而建立一個功能齊全的開發環境。該延伸模組讓您可以在 VS Code 中的容器內(或掛載到容器中)開啟專案,並在那裡享有其完整的功能集。
對於以下步驟,請確保您的機器上已安裝以下必要條件:
必要條件
建立 Dev 容器設定
-
開啟指令選擇區並執行 Dev Containers: Add Dev Container Configuration Files…。
-
選擇 Python 3。

-
選擇預設版本。
-
選擇 Redis Server 作為要安裝的額外功能,按下 OK,然後選擇 Keep Defaults。
我們可以選擇安裝要包含在容器中的功能 (Features)。在本教學中,我們將安裝 Redis Server,這是一個社群貢獻的功能,它會安裝並為 Redis 加入正確的開發容器設定。

這會在您的工作區中建立一個
.devcontainer資料夾,其中包含一個devcontainer.json檔案。讓我們對此檔案進行一些編輯,以便容器設定包含例如安裝我們所需的 VS Code 延伸模組以及專案依賴項等步驟。 -
開啟
devcontainer.json檔案。 -
在
"features" : { ... }項目後加入一個 ",",這樣我們就可以將更多設定加入到檔案中。接著,我們將把必要的依賴項安裝指令加入到
devcontainer.json檔案中的postCreateCommand屬性,以便容器設定完成後,我們的應用程式即可執行。 -
找到下方的內容,並從該行移除註解 (
//),以便在容器建立後安裝依賴項。"postCreateCommand": "pip3 install --user -r requirements.txt",您可以在 Development Containers Specification 中了解更多關於
postCreateCommand和其他生命週期腳本的資訊。現在我們將使用
customizations屬性來加入我們想要安裝在容器中的 VS Code 延伸模組。 -
將以下設定加入
devcontainer.json。// Use 'postCreateCommand' to run commands after the container is created. "postCreateCommand": "pip3 install --user -r requirements.txt", // Configure tool-specific properties. "customizations": { "vscode": { "extensions": [ "ms-python.python", //Python extension ID "ms-python.vscode-pylance" //Pylance extension ID ] } } -
儲存檔案。
-
選擇右下角顯示的通知中的 Reopen in Container,或從指令選擇區執行 Dev Containers: Reopen in Container 指令。
注意:建置容器可能需要幾分鐘的時間,具體取決於網際網路速度和機器效能。
您可以在 Dev Containers 文件中了解更多關於開發容器設定的資訊。
完成後,您將擁有一個已安裝 Python 3 和 Redis Server 的全配置 Linux 環境工作區。
容器設定完成後,您會注意到 VS Code 左下角出現一個指示器。

注意:請透過開啟延伸模組檢視(⇧⌘X (Windows, Linux Ctrl+Shift+X))並搜尋它們,再次檢查 Python 和 Pylance 延伸模組是否已成功安裝在容器中。如果沒有,您可以透過執行 Install in Dev Container 來安裝它們。
選定的 Python 解譯器資訊可在右下角的狀態列上找到,與 devcontainer.json 檔案中指定的版本相符。

注意:如果您在狀態列上找不到 Python 解譯器資訊,可以點選 Python 解譯器指示器(或從指令選擇區執行 Python: Select Interpreter 指令)並手動選擇容器中的 Python 解譯器。
我們現在準備進入下一個章節,我們將在那裡替換資料儲存方式。
替換資料庫
我們有一個儲存購物清單項目的字典,但我們想要將其替換為 Redis 資料庫。在本教學中,我們將使用 Redis 雜湊 (hashes) 來儲存我們的資料,這是一種可以儲存多個鍵值對的資料結構。
與傳統資料庫不同(在傳統資料庫中,您可以不需要知道 ID 即可擷取項目),您需要知道 Redis 雜湊鍵才能從中擷取值。在本教學中,我們將建立一個名為 item_name_to_id 的雜湊來按名稱擷取項目,並將其對應至 ID。此外,我們將建立其他雜湊來按 ID 擷取項目,將其對應至名稱和數量。每個項目雜湊命名為 item_id:{item_id},並具有兩個欄位:item_name 和 quantity。
首先,讓我們從將字典替換為連線至 Redis 伺服器的 Redis 客戶端物件開始。
-
在
main.py檔案中,將檔案開頭的grocery_list: dict[int, ItemPayload] = {}取代為下方的幾行。redis_client = redis.StrictRedis(host='0.0.0.0', port=6379, db=0, decode_responses=True)Pylance 會顯示錯誤訊息,因為 Redis 尚未匯入。
-
將游標放在編輯器中的 "redis" 上,並點選顯示的燈泡(或 ⌘. (Windows, Linux Ctrl+.))。然後選擇 Add 'import redis'。

提示:您可以透過在設定編輯器(⌘, (Windows, Linux Ctrl+,))中尋找 Auto Import Completions 設定並啟用它,來設定 Pylance 自動加入匯入。
我們現在有一個 Redis 客戶端物件,它連線至執行於本機主機(
host="0.0.0.0")且接聽連接埠 6379(port=6379)的 Redis 伺服器。db參數指定要使用的 Redis 資料庫。Redis 支援多個資料庫,在此程式碼中,我們將使用預設的資料庫 0。我們也傳入decode_responses=True,以便將回應解碼為字串(而不是位元組)。讓我們在第一個路由
add_item中做更多的取代工作。我們不需要檢視字典中的所有鍵來尋找所提供的項目名稱,而是可以直接從 Redis 雜湊中擷取該資訊。我們假設
item_name_to_id雜湊已經存在,將項目名稱對應至其 ID(別擔心,我們稍後會加入這段程式碼!)。然後,我們就可以透過呼叫 Redis 的hget方法,取得請求中接收到的項目名稱對應的 ID。如果請求的名稱已存在於雜湊中,該方法將會傳回項目 ID;如果不存在,則會傳回None。 -
刪除包含以下內容的行:
items_ids = {item.item_name: item.item_id if item.item_id is not None else 0 for item in grocery_list.values()}並將其取代為:
item_id = redis_client.hget("item_name_to_id", item_name)請注意,Pylance 對此變更提出了問題。這是因為
hget方法會傳回str或None(如果項目不存在)。然而,我們尚未替換的程式碼下方的行,預期item_id是int類型。讓我們透過重新命名item_id符號來解決此警告。 -
將
item_id重新命名為item_id_str。 -
如果您已啟用鑲嵌提示,Pylance 應該會在
item_id_str旁邊顯示變數型別提示。您可以選擇按兩下以接受它。
-
如果項目不存在,則
item_id_str為None。所以現在我們可以刪除包含以下內容的行:if item_name in items_ids.keys():並將其取代為:
if item_id_str is not None:現在我們已經有了字串格式的項目 ID,我們需要將其轉換為
int並更新項目的數量。目前,我們的 Redis 雜湊僅將項目名稱對應至其 ID。為了也能將項目 ID 對應至其名稱和數量,我們將為每個項目建立一個單獨的 Redis 雜湊,使用"item_id:{item_id}"作為我們的雜湊名稱,以方便按 ID 擷取。我們還會為每個雜湊加入item_name和quantity欄位。 -
刪除
if區塊內的程式碼:item_id: int = items_ids[item_name] grocery_list[item_id].quantity += quantity並加入以下內容,將
item_id轉換為int,然後透過呼叫 Redis 的hincrby方法來增加項目的數量。此方法會將"quantity"欄位的值增加請求中給定的數量 (quantity)。item_id = int(item_id_str) redis_client.hincrby(f"item_id:{item_id}", "quantity", quantity)我們現在只需要替換當項目不存在,即
item_id_str為None時的程式碼。在這種情況下,我們產生一個新的item_id,為項目建立一個新的 Redis 雜湊,然後加入提供的項目名稱和數量。為了產生一個新的
item_id,讓我們使用 Redis 的incr方法,傳入一個名為"item_ids"的新雜湊。此雜湊用於儲存最後產生的 ID,這樣我們就可以在每次建立新項目時將其遞增,確保它們都有唯一的 ID。 -
刪除包含以下內容的行:
item_id: int = max(grocery_list.keys()) + 1 if grocery_list else 0並加入以下內容:
item_id: int = redis_client.incr("item_ids")當這個
incr呼叫第一次使用item_ids鍵執行時,Redis 會建立該鍵並將其對應至值1。然後,在後續每次執行時,它會將儲存的值增加 1。現在我們將使用
hset方法,並提供欄位(item_id、item_name和quantity)的對應,以及值(項目新建立的 ID,以及其提供的名稱和數量),將項目加入 Redis 雜湊。 -
刪除包含以下內容的行:
grocery_list[item_id] = ItemPayload( item_id=item_id, item_name=item_name, quantity=quantity )並將其取代為以下內容:
redis_client.hset( f"item_id:{item_id}", mapping={ "item_id": item_id, "item_name": item_name, "quantity": quantity, })現在我們只需要透過設定我們在開頭提到的雜湊
item_name_to_id,將新建立的 ID 對應至項目名稱即可。 -
在
else區塊內,將此行加入到路由的結尾。redis_client.hset("item_name_to_id", item_name, item_id) -
刪除包含以下內容的行:
return {"item": grocery_list[item_id]}並將其取代為:
return {"item": ItemPayload(item_id=item_id, item_name=item_name, quantity=quantity)} -
如果願意,您可以嘗試為其他路由執行類似的替換。否則,您可以直接將檔案的全部內容取代為下方的幾行。
import redis from fastapi import FastAPI, HTTPException from models import ItemPayload app = FastAPI() redis_client = redis.StrictRedis(host="0.0.0.0", port=6379, db=0, decode_responses=True) # Route to add an item @app.post("/items/{item_name}/{quantity}") def add_item(item_name: str, quantity: int) -> dict[str, ItemPayload]: if quantity <= 0: raise HTTPException(status_code=400, detail="Quantity must be greater than 0.") # Check if item already exists item_id_str: str | None = redis_client.hget("item_name_to_id", item_name) if item_id_str is not None: item_id = int(item_id_str) redis_client.hincrby(f"item_id:{item_id}", "quantity", quantity) else: # Generate an ID for the item item_id: int = redis_client.incr("item_ids") redis_client.hset( f"item_id:{item_id}", mapping={ "item_id": item_id, "item_name": item_name, "quantity": quantity, }, ) # Create a set so we can search by name too redis_client.hset("item_name_to_id", item_name, item_id) return { "item": ItemPayload(item_id=item_id, item_name=item_name, quantity=quantity) } # Route to list a specific item by ID but using Redis @app.get("/items/{item_id}") def list_item(item_id: int) -> dict[str, dict[str, str]]: if not redis_client.hexists(f"item_id:{item_id}", "item_id"): raise HTTPException(status_code=404, detail="Item not found.") else: return {"item": redis_client.hgetall(f"item_id:{item_id}")} @app.get("/items") def list_items() -> dict[str, list[ItemPayload]]: items: list[ItemPayload] = [] stored_items: dict[str, str] = redis_client.hgetall("item_name_to_id") for name, id_str in stored_items.items(): item_id: int = int(id_str) item_name_str: str | None = redis_client.hget(f"item_id:{item_id}", "item_name") if item_name_str is not None: item_name: str = item_name_str else: continue # skip this item if it has no name item_quantity_str: str | None = redis_client.hget( f"item_id:{item_id}", "quantity" ) if item_quantity_str is not None: item_quantity: int = int(item_quantity_str) else: item_quantity = 0 items.append( ItemPayload(item_id=item_id, item_name=item_name, quantity=item_quantity) ) return {"items": items} # Route to delete a specific item by ID but using Redis @app.delete("/items/{item_id}") def delete_item(item_id: int) -> dict[str, str]: if not redis_client.hexists(f"item_id:{item_id}", "item_id"): raise HTTPException(status_code=404, detail="Item not found.") else: item_name: str | None = redis_client.hget(f"item_id:{item_id}", "item_name") redis_client.hdel("item_name_to_id", f"{item_name}") redis_client.delete(f"item_id:{item_id}") return {"result": "Item deleted."} # Route to remove some quantity of a specific item by ID but using Redis @app.delete("/items/{item_id}/{quantity}") def remove_quantity(item_id: int, quantity: int) -> dict[str, str]: if not redis_client.hexists(f"item_id:{item_id}", "item_id"): raise HTTPException(status_code=404, detail="Item not found.") item_quantity: str | None = redis_client.hget(f"item_id:{item_id}", "quantity") # if quantity to be removed is higher or equal to item's quantity, delete the item if item_quantity is None: existing_quantity: int = 0 else: existing_quantity: int = int(item_quantity) if existing_quantity <= quantity: item_name: str | None = redis_client.hget(f"item_id:{item_id}", "item_name") redis_client.hdel("item_name_to_id", f"{item_name}") redis_client.delete(f"item_id:{item_id}") return {"result": "Item deleted."} else: redis_client.hincrby(f"item_id:{item_id}", "quantity", -quantity) return {"result": f"{quantity} items removed."} -
重新執行偵錯器,透過與
/docs路由互動來測試此應用程式。完成後,您可以停止偵錯器。
恭喜!您現在擁有一個運作中的 FastAPI 應用程式,且具備新增、列出和刪除購物清單項目的路由,且資料已持久化在 Redis 資料庫中。
選用:設定資料庫刪除
由於資料現在由 Redis 持久化,您可能會想要建立一個指令碼來清除所有測試資料。為此,請建立一個名為 flushdb.py 的新檔案,並包含以下內容:
import redis
redis_client = redis.StrictRedis(host='0.0.0.0', port=6379, db=0, decode_responses=True)
redis_client.flushdb()
然後,當您想要重置資料庫時,您可以在 VS Code 中開啟 flushdb.py 檔案,並選擇編輯器右上角的 執行 按鈕,或從指令選擇區執行 Python: Run Python File in Terminal 指令。
請注意,執行此操作應格外小心,因為這將刪除目前資料庫中的所有鍵,若在生產環境執行可能會導致資料遺失。
選用:建立 GPT Action
使用 GitHub Codespaces,您可以在使用 GPT Actions 時託管您的應用程式以進行測試。GPT Actions 是讓 ChatGPT 與現有 API 互動以增強 ChatGPT 能力的工具,允許它執行廣泛的動作。您可以依照下方的直播錄影來建立您自己的 ChatGPT 購物清單外掛。
注意:所有個人 GitHub.com 帳戶在 Free 或 Pro 方案中都包含每月免費使用 GitHub Codespaces 的額度。如需更多資訊,請前往 關於 GitHub Codespaces 的計費。
後續步驟
感謝您閱讀本教學!我們希望您學到了關於 FastAPI 以及如何將其與 VS Code 搭配使用的新知識。
本教學的完整專案程式碼可在 GitHub 上找到:python-sample-vscode-fastapi-tutorial。
在官方文件了解更多關於 FastAPI 的資訊。
若要嘗試在生產網站上執行應用程式,請查看教學 使用 Docker 容器將 Python 應用程式部署到 Azure App Service。
您也可以查閱這些其他 VS Code Python 文章。