在Visual Studio Code中使用FastAPI教程
FastAPI 是一个用 Python 构建 API 的现代高性能 Web 框架。它旨在使快速高效地构建 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 扩展讨论 Q&A上提问。
设置项目
有不同的方法可以为本教程设置项目。我们将涵盖如何在 GitHub Codespaces 和在 本地机器上的 VS Code 中设置。
GitHub 代码空间
您可以设置此项目以在 GitHub Codespaces 中开发,您可以在 codespace 中远程编码、调试和运行您的应用程序。 codespace 提供了一个托管在云端的完全配置的开发环境,消除了本地设置的需要。此环境包括项目依赖项、工具和扩展,确保一致且可重复的开发体验。它通过提供实时编辑、集成版本控制和轻松访问调试和测试工具,简化了协作,同时保持项目的安全性和可靠性。
注意:所有 GitHub.com 账户在免费或专业计划中都包含每月免费使用的 GitHub Codespaces 配额。有关更多信息,请访问 关于 GitHub Codespaces 的计费。
要为本教程设置一个代码空间,请导航到本项目的GitHub仓库。这个代码空间包含所有必要的配置和依赖项,可以快速开始FastAPI开发。
对于这个教程,选择基于字典的分支:

然后,选择代码 > 代码空间 > 在<dictionarybased>分支上创建并打开项目代码空间。
完成后,您可以继续进行替换数据库部分。
在 VS Code 中本地
要成功完成此教程,你需要在VS Code中设置你的Python开发环境。具体来说,此教程需要:
- Python 3(如果没有安装,请查看安装指南)
- VS Code的Python扩展(有关安装扩展的更多详细信息,您可以阅读扩展市场)。
在本节中,我们将创建一个文件夹,以在 VS Code 中打开为工作区,设置 Python 虚拟环境,并安装项目依赖项。
-
在你的文件系统中,为本教程创建一个项目文件夹,例如
杂货插件输入:. -
在 VS Code 中打开这个新文件夹 (文件 > 打开文件夹…).
-
当 工作区信任 提示出现时,选择 是的,我信任作者 以允许工作区访问必要的资源和扩展。您可以在 文档 中了解更多关于工作区信任的信息。
现在,让我们创建一个要求.txt列出我们希望为应用程序安装的依赖项的文件。要求.txt文件是Python开发中常见的做法,用于指定项目所依赖的库及其版本。这个文件有助于确保任何参与项目的人都可以重现类似的开发环境,使其成为维护一致性的方便组件。
我们将安装FastAPI来创建应用程序,uvicorn作为服务器,以及Redis和类型-Redis用于处理数据存储和与Redis数据库交互。
-
在 VS Code 中创建新文件 (文件 > 新建文本文件 或 ⌘N (Windows, Linux Ctrl+N))。
-
添加以下内容:
fastapi Redis types-redis uvicorn -
保存文件 (⌘S (Windows, Linux Ctrl+S)) 并命名它
要求.txt输入:. -
通过打开命令面板 (⇧⌘P (Windows, Linux Ctrl+Shift+P)) 并运行 Python: 创建环境 命令来创建一个虚拟环境。
注意:这一步可能需要几分钟才能完成。
-
当被问及环境类型时,选择 Venv:

-
然后选择您机器上可用的最新版本的Python:

-
选择
要求.txt从下拉列表中选择文件,以便自动安装依赖项,然后选择 确定:
虚拟环境将被创建,依赖项将自动安装,并且为你的工作区选择的环境将被Python扩展使用。你可以在VS Code右下角确认它已被选择:

注意:如果在状态栏中找不到新创建的环境信息,您可以点击Python解释器指示器(或从命令面板中运行Python:选择解释器命令),并手动选择虚拟环境。
开始编码
让我们创建应用程序!
-
通过使用文件 > 新建文件…来创建一个新的Python文件,然后选择Python文件.
-
保存为
main.py(⇧⌘S (Windows, Linux Ctrl+Shift+S)) 在杂货插件文件夹。 -
将以下代码添加到
main.py并保存文件:从 fastapi 导入 FastAPI app = FastAPI() @app.get("/") def root(): return {"message": "Hello World"} -
通过启动调试器(F5)运行代码。
-
从下拉菜单中,选择 FastAPI 配置选项:

这会自动生成一个调试配置,通过调试器调用uvicorn启动应用服务器,并允许您逐步执行源代码以检查其行为。您应该在终端中看到如下内容:

提示:如果默认端口已被使用,请停止调试器并打开命令面板 (⇧⌘P (Windows, Linux Ctrl+Shift+P)),搜索 调试:添加配置,选择 Python 调试器,然后 FastAPI。这将在
.vscode/launch.json可以编辑的。在以下位置添加以下内容"args":[]要设置自定义端口:"--port=5000"保存文件,并使用(F5)重启调试器。 -
Ctrl+点击
http://127.0.0.1:8000/在终端中输入URL以打开默认浏览器:
恭喜!您的 FastAPI 应用程序已经启动并运行!
-
通过点击调试工具栏中的停止按钮来停止调试器,或者通过⇧F5(Windows, LinuxShift+F5)。
创建一个杂货清单项目的模型
既然我们已经让 FastAPI 应用程序正常工作,我们就可以使用 Pydantic 来定义我们的杂货清单项目,这是一款与 FastAPI 完美集成的数据验证和解析库。Pydantic 允许您使用 Python 类和 类型提示 来定义数据模型,从而自动验证和解析 API 请求中传入的数据(称为“有效负载”)。
让我们为我们的杂货清单项目创建一个模型。我们将使用项目载荷用于定义要添加到购物清单中的项目数据结构的模型。该模型将有三个字段:商品编号,商品名称,和数量输入:.
-
创建一个新的Python文件,通过文件 > 新建文件…,然后选择Python文件。
-
将以下内容添加到文件中,然后保存在
杂货插件文件夹作为models.py(⇧⌘S (Windows, Linux Ctrl+Shift+S)):从 输入 导入 可选 从 pydantic 导入 基本模型 类 项负载(基础模型): 项ID: 可选的[整数] 项名称: 字符串 数量: 整数
Pylance,是 VS Code 中 Python 的默认语言服务器,支持类型提示功能,这在处理 Pydantic 模型和 FastAPI 时非常有用。这是因为 Pylance 是基于 Pyright 构建的,Pyright 是一个静态类型检查器,可以检测代码中的类型错误,以防止出现错误并提高代码质量。
以下是三个可选步骤,但鉴于 FastAPI 广泛使用类型提示来提高代码可读性和验证性,我们可以利用 Pylance 的类型检查功能尽早发现错误:
-
打开设置编辑器 (⌘, (Windows, Linux Ctrl+,)).
-
搜索 "python type checking mode" 并将其设置为
基本用于基本类型检查。Pylance 现在会显示诊断和警告来捕捉简单的类型相关错误。或者,您可以将其设置为严格以实施更先进的 类型检查规则。
-
接下来,搜索 "Python 在lay 类型提示",并启用 变量类型 和 函数返回类型 的 inlay 提示:

创建路线
现在我们需要一个地方来存储杂货清单项目。为了简单起见,我们从一个空字典开始。
-
首先,让我们导入所有需要的包来创建示例。打开
main.py文件并用以下语句替换第一行导入语句:从 fastapi 导入 FastAPI, HTTPException 从 模型 导入 项目负载 -
现在在下面添加以下行
app = FastAPI()输入:购物清单: dict[int, 项目信息] = {}这创建了一个新的空字典,该字典接收类型为的键
整数(作为项目ID)和值项目载荷类型。现在我们将在 FastAPI 应用程序中定义路由。在网页应用的背景下,路由就像是将特定的 URL 映射到处理它的代码的路径。这些路由是我们应用中不同功能的入口点。当客户端(如网页浏览器或其他程序)使用特定的 URL 向我们的应用发送请求时,FastAPI 会根据 URL 将该请求路由到相应的函数(也称为路由处理程序或视图函数),然后该函数处理请求并生成响应。
让我们定义用于添加和检索单个项目以及返回杂货清单中所有项目的路由。
-
在末尾添加以下路由
main.py文件:# Route to add a 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 ) 返回 {"项目": 购物清单[item_id]}如果你在上一节中启用了类型提示,你可能会注意到 Pylance 添加了函数返回类型以及参数类型的内联提示。
商品编号和商品编号您可以选择双击每个建议将其插入代码中:
现在让我们检查一下这个路由是否按预期工作。最快的方法是使用 VS Code 的调试器以及 FastAPI 的
/docs端点,提供所有可用的 API 路由信息,并允许您与 API 互动以探索其参数和响应。此文档是根据 FastAPI 应用程序中定义的元数据和类型提示动态生成的。 -
在旁边添加一个断点
如果数量 <= 0语句,点击行号的左边缘(或 F9)。调试器将在该行执行之前停止,因此您可以逐行检查代码。
-
启动调试器 (F5),然后导航到
http://127.0.0.1:8000/docs在浏览器中。应该有一个Swagger接口,其中包含应用中的两个端点:
/物品和根输入:/)。
-
选择旁边的下拉箭头
/物品扩展它的路线,然后点击 试一试 按钮,该按钮会出现在右侧。
-
通过传递字符串向购物清单添加一项
商品名称字段和一个数字到数量例如,您可以提供苹果作为商品名称和2作为数量输入:. -
选择 执行.

-
再次打开 VS Code,注意到调试器已经停在了你之前设置的断点。

在左侧,此点定义的所有局部和全局变量都在变量Windows中显示,位于运行和调试视图下。在我们的示例中,
商品名称设置为 'apple' 和数量在局部变量视图中设置为2,同时出现一个空购物清单全局变量视图下的字典。
现在让我们使用 VS Code 的调试控制台进行一些探索。
-
选择
数量 <= 0语句,右键单击编辑器并选择 在调试控制台中评估:
这将打开调试控制台并运行所选表达式。如我们预期的那样,在我们的示例中,表达式评估为
假输入:.调试控制台可以成为快速测试表达式并更好地理解在断点时代码状态的强大工具。您还可以用它来运行任意代码,例如调用函数或打印变量。您可以在Python教程中了解更多关于在VS Code中使用Python调试的信息。
您现在可以通过选择 继续 在调试视图工具栏中,或者按 F5 来继续执行代码。
最后,让我们为应用程序添加剩余的路由,以便我们可以列出所有项目或特定项目,并将其从我们的购物清单中删除。你可以让调试器保持运行状态,因为它会在你保存在下一步中所做的更改时自动重新加载应用程序。
-
替换内容
main.py使用以下代码:从 fastapi 导入 FastAPI, HTTPException 从 模型 导入 项目负载 app = FastAPI() 购物清单: dict[int, 项目信息] = {} # 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 grocery_list[item_id].quantity <= quantity: del grocery_list[item_id] return {"result": "物品已删除。"} else: grocery_list[item_id].quantity -= quantity return {"result": f"{quantity} 个物品已移除。"} -
保存文件 (⌘S (Windows, Linux Ctrl+S))。应用程序应自动重新加载。
您现在可以打开/docs 再次访问页面并测试新路由,使用调试器和调试控制台更好地理解代码执行。完成后,可以停止调试器 (⇧F5 (Windows, Linux Shift+F5))。你也可以点击断点来移除我们在第4步中添加的断点。
恭喜!您现在有一个可以添加、列出和删除购物清单项目的 FastAPI 应用程序。
设置数据存储
此时,您已经拥有一个具有基本功能的可运行版本的应用程序。本节将指导您设置数据存储以实现持久化,但如果您已经掌握足够的知识,可以选择跳过。
到目前为止,我们正在将数据存储在字典中,这不是理想的方法,因为当应用程序重新启动时,所有数据都会丢失。
为了持久化数据,我们将使用Redis,这是一个开源的内存数据结构存储。由于其速度和多功能性,Redis 广泛用于各种应用中的数据存储系统,包括网络应用、实时分析系统、缓存层、本教程等。
如果您已经在GitHub Codespaces中使用我们的现有模板工作,您可以直接跳到替换数据库部分。
如果你在Windows系统上,你可以通过设置一个Docker容器或者一个GitHub Codespace来使用Redis。在这个教程中我们将使用Docker容器,但你可以参考上面的章节来获取如何设置GitHub Codespace的说明。
否则,如果您在 Linux 或 macOS 机器上,可以通过 其网站上的说明 来安装 Redis,然后跳到 替换数据库 部分。
在 Windows 上设置 Docker 容器
VS Code Dev Containers 扩展提供了一种简化的方法,将您的项目、其依赖项和所有必要的工具整合到一个整洁的容器中,创建一个功能齐全的开发环境。该扩展允许您在 VS Code 中打开项目(或挂载到容器中),在那里您将拥有其全部功能集。
对于以下步骤,请确保您的机器上安装了以下要求:
要求
创建开发容器配置
-
打开命令面板并运行开发容器:添加开发容器配置文件....
-
选择 Python 3:

-
选择默认版本。
-
选择 Redis 服务器 作为附加功能进行安装,按 确定,然后选择 保持默认值。
我们可以选择性地安装功能,以包含在容器中。对于本教程,我们将安装Redis 服务器,这是一个社区贡献的功能,用于安装并添加 Redis 的正确开发容器设置。

这创造了
.devcontainer在你的工作区中创建一个文件夹,并添加一个devcontainer.json文件。让我们对这个文件进行一些编辑,以便容器设置包括安装我们需要的 VS Code 扩展以及项目依赖项等步骤。 -
打开
devcontainer.json文件。 -
在...后添加一个","
"features" : { ... }条目,以便我们可以向文件中添加更多设置。接下来,我们将向文件中添加必要的依赖项安装命令
创建命令后物业在devcontainer.json文件,因此我们的应用程序在容器设置好后就可以运行。 -
找到下面的内容并删除注释
输入://) 从那行,以便在容器创建后可以安装依赖项:"postCreateCommand": "pip3 install --user -r requirements.txt",你可以了解
创建命令后并且在 开发容器规范 中有更多生命周期脚本。现在我们将使用
定制属性用于添加我们希望在容器中安装的 VS Code 扩展。 -
添加以下设置到
devcontainer.json输入:// 使用 'postCreateCommand' 在容器创建后运行命令。 "postCreateCommand": "pip3 install --user -r requirements.txt", // 配置特定工具的属性。 "customizations": { "vscode": { "extensions": [ "ms-python.python", //Python 扩展 ID "ms-python.vscode-pylance" //Pylance 扩展 ID ] } } -
保存文件。
-
选择 在容器中重新打开 在右下角显示的通知中,或从命令面板中运行 开发容器:在容器中重新打开 命令。
注意:根据互联网速度和机器性能,构建容器可能需要几分钟时间。
您可以在开发容器文档中了解更多关于开发容器配置的信息。
完成后,您将拥有一个完全配置好的基于Linux的工作区,其中安装了Python 3和Redis服务器。
一旦容器设置完成,您将在 VS Code 的左下角看到一个指示器:

注意:再次确认Python和Pylance扩展是否已成功安装在容器中,可以通过打开扩展视图 (⇧⌘X (Windows, Linux Ctrl+Shift+X)) 并搜索它们。如果没有,请通过运行 在开发容器中安装 来安装它们。
所选的Python解释器信息可在右下角的状态栏中查看,与指定版本匹配。devcontainer.json文件:

注意:如果在状态栏上找不到Python解释器信息,您可以点击Python解释器指示器(或从命令面板中运行Python:选择解释器命令),并手动在容器中选择Python解释器。
我们现在准备继续进行下一节,我们将替换数据存储。
替换数据库
我们有一个存储杂货清单项目的字典,但我们现在想用Redis数据库替换它。在这个教程中,我们将使用Redis哈希来存储我们的数据,这是一种可以存储多个键值对的数据结构。
与传统数据库不同,您可以在不知道其ID的情况下检索项目,您需要知道Redis哈希键才能从其中检索值。在本教程中,我们将创建一个名为的哈希商品名称到ID要通过名称检索项目,并将其映射到其ID。此外,我们将创建其他哈希,以便通过ID检索项目,将其映射到其名称和数量。每个项目哈希的名称是商品编号:{商品编号}并且有两个字段:商品名称和数量输入:.
首先,让我们通过连接到Redis服务器的Redis客户端对象来替换字典。
-
在
main.py文件,替换购物清单:字典[整数, 项目数据] = {}在文件开头用下面的行:redis_client = redis.StrictRedis(host='0.0.0.0', port=6379, db=0, decode_responses=True)Pylance将显示错误消息,因为Redis尚未导入。
-
在编辑器中将光标放在 "redis" 上,然后点击显示的灯泡(或 ⌘.(Windows, Linux Ctrl+.))。然后选择 添加 'import redis'。

提示:您可以通过在设置编辑器中查找自动导入补全设置(⌘,(Windows, Linux Ctrl+)),并启用它来自动添加导入。
我们现在有一个Redis客户端对象,它连接到本地主机上的Redis服务器 (
主机="0.0.0.0") 并在端口 6379 上监听 (端口=6379)。 The数据库参数指定了要使用的Redis数据库。Redis支持多个数据库,这段代码我们将使用数据库0,这是默认数据库。我们还在传递解码响应=True为了将响应解码为字符串(而不是字节)。让我们在第一条路线中进行更多的替换
添加项目. 与其查看字典中的所有键以找到已提供的项目名称,我们可以直接从Redis哈希中获取该信息。我们将假定该
商品名称到ID哈希已经存在,将项目名称映射到它们的ID(别担心,我们很快会添加此代码!)。然后,我们可以调用通过请求接收的项目名称来获取其ID。获取键的值方法来自Redis,如果请求的名称在哈希中已存在,将返回项目ID,否则无如果它不。 -
删除包含以下内容的行:
items_ids = {item.item_name: item.item_id 如果 item.item_id 不是 无 否则 0 对于 item 在 grocery_list.values()}并替换为:
item_id = redis_client.hget("item_name_to_id", item_name)请注意,Pylance 对此更改提出了一个问题。这是因为
获取键的值方法返回其中任何一个输入:str,或无(如果该物品不存在)。然而,我们尚未替换的代码下面的行期望商品编号类型整数让我们通过重命名来解决这个警告商品编号符号。 -
重命名
商品编号至商品编号字符串输入:. -
如果你启用了嵌入式提示,Pylance 应该在旁边显示一个变量类型提示
商品编号字符串您可以选择双击以接受它:
-
如果该物品不存在,则
商品编号字符串是无所以现在我们可以删除包含以下内容的行:如果 项目名称 在 项目_ids.keys()中:并替换为:
如果 item_id_str 不是 空 无:既然我们已经将物品ID转换为字符串,接下来我们需要将其转换为一个
整数并更新该商品的数量。目前,我们的Redis哈希仅将商品名称映射到其ID。为了同时将商品ID映射到其名称和数量,我们将为每件商品创建一个单独的Redis哈希,使用"商品编号:{item_id}"将我们的哈希名称用于通过ID进行检索。我们还将添加商品名称和数量这些哈希的字段。 -
删除代码内的
如果块:商品编号: 整数 = 商品编号[商品名称] 杂货清单[商品编号].数量 += 数量并添加以下内容,以进行转换
商品编号到一个整数,然后通过调用 增加该商品的数量增加方法来自Redis。该方法增加键的值"数量"在请求中按给定数量调整字段数量):item_id = int(item_id_str) redis_client.hincrby(f"item_id:{item_id}", "数量", quantity)我们现在只需要替换项目不存在时的代码,当
商品编号字符串是无在这种情况下,我们生成一个新的商品编号创建一个新的Redis哈希来存储该商品,并添加提供的商品名称和数量。生成一个新的
商品编号,让我们使用增加方法来自Redis,传递一个名为的新哈希"商品编号"这个哈希被用来存储最后生成的ID,这样我们每次创建新项目时就可以增加这个ID,确保它们都有一个唯一的ID。 -
删除包含以下内容的行:
商品编号: 整数 = 最大(杂货清单.keys()) + 1 如果 杂货清单 否则 0并添加以下内容:
item_id: 整数 = redis_client.incr("item_ids")当这
增加调用第一次运行商品编号键,Redis 创建键并将值映射到该键1然后,每次运行时,它将存储的值增加1。现在我们将把项目添加到Redis哈希中,使用
设置哈希方法并为字段提供映射商品编号,商品名称,和数量),和值(项目新创建的ID,以及其提供的名称和数量)。 -
删除包含以下内容的行:
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, })现在我们只需要通过设置我们最初引用的哈希将新创建的ID映射到项目名称。
商品名称到ID输入:. -
将此行添加到路线的末尾,内部
否则块:redis_client.hset("商品名称到ID", 商品名称, 商品ID) -
删除包含以下内容的行:
返回 {"商品": 购物清单[item_id]}并替换为:
返回 {"项目": 项目负载(项目ID=项目ID, 项目名称=项目名称, 数量=数量)} -
如果你愿意,你可以尝试对其他路线进行类似的替换。否则,你可以直接将文件的内容替换为下面的几行:
导入 redis 从 fastapi 导入 FastAPI, HTTPException 从 模型 导入 项目负载 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包含以下内容:
导入 redis
redis_client = redis.StrictRedis(host='0.0.0.0', port=6379, db=0, decode_responses=True)
redis_client.flushdb()
然后,当您想重置数据库时,您可以打开flushdb.py 在 VS Code 中打开文件并选择编辑器右上角的 运行 按钮,或者从命令面板中运行 Python: 在终端中运行 Python 文件 命令。
请注意,这需要谨慎进行,因为它将删除当前数据库中的所有键,如果在生产环境中执行,可能会导致数据丢失。
可选:创建一个GPT动作
使用 GitHub Codespaces,当使用 GPT Actions 时,您可以为测试目的托管您的应用程序。GPT Actions 是一种工具,使 ChatGPT 能够与现有 API 互动,以增强 ChatGPT 的功能,使其能够执行广泛的行动。您可以在下面观看直播录像,创建您自己的 ChatGPT 购物清单插件:
注意:所有个人 GitHub.com 帐户在免费或专业计划中都包含每月免费使用的 GitHub Codespaces 配额。有关更多信息,请访问 关于 GitHub Codespaces 的计费。
下一步
感谢您跟随这个教程!我们希望您学到了关于 FastAPI 和如何使用 VS Code 的一些新知识。
本教程完成的代码项目可以在GitHub上找到:python-sample-vscode-fastapi-tutorial.
了解更多关于FastAPI的信息,请访问官方文档。
要在一个生产网站上试用该应用程序,请查看教程使用Docker容器将Python应用程序部署到Azure App Service.
您还可以查看这些其他 VS Code Python 文章: