自在学

我们与你共同进步

  • 分类课程
  • 文章
  • 工作台
  • 订阅

  • 关于我们
  • 隐私政策
  • 使用条款

探索

  • 分类课程
  • 文章
  • 工作台
  • 订阅

网站信息

  • 关于我们
  • 隐私政策
  • 使用条款

加入社区

自在学学习社区微信二维码

微信扫码,交流学习

株洲市自在学教育科技有限公司© 2025 - 2026 版权所有

© 2025 - 2026 株洲市自在学教育科技有限公司 版权所有

湘公网安备43020302000292号|湘ICP备2025148919号-1
分类课程工作台文章订阅
分类课程工作台文章价格

FastAPI 后端开发

  1. 01FastAPI 和 RESTful API 概览
  2. 02搭建开发环境与安装 FastAPI
  3. 03FastAPI 核心特性
  4. 04依赖注入
  5. 05使用 Pydantic 定义请求与响应模型
  6. 06身份验证与授权
  7. 07文件上传
  8. 08连接数据库
  9. 09测试与调试
  10. 10部署与扩展
  11. 11应用配置管理
  12. 12FastAPI 的未来发展
正在加载课程章节内容
课程编程FastAPI 后端开发搭建开发环境与安装 FastAPI

搭建开发环境与安装 FastAPI

这一章不打算先把一堆工具名塞给你。我们要完成的是一个非常具体的结果:在一个干净的项目目录里准备 Python,隔离依赖,安装 FastAPI,写出两个接口,再亲眼看到服务器、响应和交互文档都正常工作。

第一次搭环境最容易出现的情况,是每条命令看起来都成功,启动时却提示找不到包;或者同一份代码在你的电脑上能跑,换到同事电脑就缺依赖。根源通常不是 FastAPI 本身,而是解释器、环境和依赖文件没有对齐。我们会把这三层逐一确认,再开始写代码。

本文以 Python 3.13、FastAPI 0.141.1 和 Uvicorn 0.52.1 完成整条流程。版本号会继续变化,你不必照抄小版本;真正要保留下来的是版本约束和锁定文件。


先确认你正在使用哪一个 Python

选择版本时看两件事

当前 FastAPI 要求 Python 3.10 或更高版本。新项目可以选择仍在维护的稳定版本;团队项目则先看仓库中的 requires-python、.python-version、持续集成配置和部署镜像,跟已有约束保持一致。版本越新不等于项目越稳,所有运行环境能使用同一条版本线才更重要。

先在终端执行:

bash
python3 --version
text
Python 3.14.6

Windows 上由官方安装器安装 Python 后,通常使用:

powershell
py --version

如果 python3、python 和 py 中只有一个能用,不需要把它们全部修成同一个命令。你只需要找出哪个命令指向准备给项目使用的 Python,后续始终使用它。

还可以直接查看解释器路径:

bash
python3 -c "import sys; print(sys.executable)"

路径会指出真正运行代码的解释器。以后遇到“明明安装了包,导入却失败”,第一件事就是重新检查这条路径,而不是继续重复安装。

不要把操作系统自带的 Python 当成项目公共仓库。系统工具可能依赖它的包和版本,直接往里面安装 Web 项目依赖,既容易产生权限问题,也可能让两个项目互相覆盖依赖。

虚拟环境隔离的到底是什么

虚拟环境是项目专用的一套 Python 运行目录。它会记录自己的解释器入口和第三方包安装位置。激活环境后,终端会优先找到这个目录里的 python 和 pip。项目甲升级某个包,不会顺手改掉项目乙使用的版本。

每个项目都有自己的解释器与依赖环境

在项目根目录创建环境:

bash
python3 -m venv .venv

macOS 与常见 Linux shell 使用:

bash
source .venv/bin/activate

Windows PowerShell 使用:

powershell
.venv\Scripts\Activate.ps1

激活不是一句仪式性的命令,它改变了当前终端查找可执行文件的顺序。验证比观察提示符更可靠:

bash
python -c "import sys; print(sys.executable)"
python -m pip --version

输出的两条路径都应包含项目的 .venv 目录。这里特意写 python -m pip,是为了让“运行 pip 的 Python”和“运行项目的 Python”明确绑定在一起。只写 pip 时,终端可能从别处找到另一个 pip。

结束工作后可以退出当前环境:

bash
deactivate

退出只会还原当前终端的路径,不会删除 .venv。下一次进入项目,重新激活即可。

把环境目录加入 .gitignore:

gitignore
.venv/
__pycache__/
.pytest_cache/
.env

.venv 体积大,里面还保存本机路径,既不适合提交,也不负责复现环境。真正应该提交的是依赖声明与锁定结果。


安装的不是一个孤立的框架

输入一条安装命令之后,包管理器会解析一棵依赖树。我们的代码使用 FastAPI 描述路由;FastAPI 使用 Starlette 处理 Web 层能力,使用 Pydantic 解析和校验数据;Uvicorn 则负责监听网络端口,把收到的请求交给应用。

从接口代码到网络请求的运行层次

这也解释了为什么只安装 fastapi 和安装 fastapi[standard] 得到的体验不同。核心包足够定义应用,但标准扩展会一并准备常见的服务器、命令行、表单解析、模板和开发辅助依赖。刚开始搭项目时,选择标准扩展可以减少“代码没问题,只是少装了运行工具”的干扰。

依赖名后面的方括号表示安装一组可选扩展,不是版本号。fastapi[standard] 仍然安装 FastAPI,只是同时选中了官方维护的标准依赖组。


两条安装路线只选一条走到底

传统的 venv + pip 很直接,适合先理解每一步发生了什么;uv 会把 Python 版本、虚拟环境、依赖声明、锁定和运行串成一套项目工作流。两条路线都能跑 FastAPI,真正容易出问题的是先用一个工具创建环境,又临时用另一个工具改依赖,最后没人知道哪个文件才是准的。

路线一:使用 venv 与 pip

完成环境创建和激活后,执行:

bash
python -m pip install "fastapi[standard]"

再确认包确实装进当前解释器:

bash
python -c 'import sys, fastapi, uvicorn; print(sys.executable); print(f"fastapi={fastapi.__version__}"); print(f"uvicorn={uvicorn.__version__}")'
text
/private/tmp/fastapi-ch02.iZzmPF/.venv-pip/bin/python
fastapi=0.141.1
uvicorn=0.52.1

第一行比后两行更关键:它证明当前命令使用项目环境中的解释器。如果那里显示系统目录,说明环境没有激活,或者你调用了错误的 Python。

小项目可以先把直接依赖写进 requirements.in:

text
fastapi[standard]

安装时使用:

bash
python -m pip install -r requirements.in

需要保存当前环境中所有精确版本时,可以生成:

bash
python -m pip freeze > requirements.txt

然后在新环境中安装:

bash
python -m pip install -r requirements.txt

freeze 会把直接依赖和间接依赖全部列出来,因此适合记录一套已经验证过的应用环境。不要把装过很多无关工具的公共环境拿来冻结,否则文件里会混入项目并不需要的包。

路线二:使用 uv 管理项目

先确认 uv 可用:

bash
uv --version
text
uv 0.9.27 (Homebrew 2026-01-26)

在空目录中初始化项目,并指定要使用的 Python 版本线:

bash
uv init --bare --python 3.13 .
text
Initialized project `fastapi-ch02-izzmpf` at `/private/tmp/fastapi-ch02.iZzmPF`

--bare 只创建最小的项目配置,不生成示例业务代码。接着添加依赖:

bash
uv add "fastapi[standard]"

这一步会同时做三件事:把直接依赖写入 pyproject.toml,解析精确版本到 uv.lock,并创建或同步项目的 .venv。关键配置会变成:

toml
[project]
name = "fastapi-ch02-izzmpf"
version = "0.1.0"
requires-python = ">=3.13"
dependencies = [
    "fastapi[standard]>=0.141.1",
]

以后不要直接进入 uv 管理的环境再随手 pip install。正式依赖用 uv add,移除依赖用 uv remove,同步环境用 uv sync,在项目环境中运行命令用 uv run。这样 pyproject.toml、uv.lock 与 .venv 才会始终对应。

如果你只是跟着本课程搭项目,我建议后续示例使用 uv 路线。它省掉手动激活这一步,同时保留清楚的依赖声明和锁定结果。想练习标准库原生流程时,再用 venv 与 pip 重做一次,两者背后的隔离逻辑是相同的。


建立一个够小但能继续长大的目录

先让目录保持简单:

text
fastapi-learning/
├── .gitignore
├── .python-version
├── .venv/
├── main.py
├── pyproject.toml
└── uv.lock

这里没有急着拆 routers、models、services。只有两个路由时,提前创建十几个空目录不会让结构更专业,反而会让第一次启动多出导入路径问题。等同类路由变多,再按职责拆包。

在 main.py 写入:

python
from fastapi import FastAPI
 
 
app = FastAPI(title="学习清单接口", version="0.1.0")
 
 
@app.get("/")
async def read_root():
    return {"message": "FastAPI 已经运行", "docs": "/docs"}
 
 
@app.get("/tasks/{task_id}")
async def read_task(task_id: int, detail: bool = False):
    return {"task_id": task_id, "detail": detail}

现在逐段看它做了什么。

app = FastAPI(...) 创建应用对象。Uvicorn 启动时要导入的就是它。title 和 version 描述的是我们自己的接口应用,会进入自动生成的接口说明。

@app.get("/") 把“根路径上的 GET 请求”交给紧随其后的函数。函数返回 Python 字典,FastAPI 会把它序列化为 JSON 响应,并设置合适的响应类型。

第二个路由同时演示了两类输入。task_id 出现在路径模板中,并标注为 int;detail 不在路径里,因此会被识别为查询参数。访问 /tasks/7?detail=true 时,FastAPI 会把字符串形式的 7 和 true 转换为 Python 的整数和布尔值,再调用函数。

你不需要为了“使用异步框架”而机械地把每个函数都写成 async def。这里使用异步函数,是为后面调用异步数据库或网络客户端预留一致写法。若函数内部调用的是只能同步等待的库,普通 def 也可以由 FastAPI 处理。真正要避免的是在 async def 内直接执行长时间阻塞操作。

先做一次纯导入检查,不启动端口:

bash
uv run python -c 'import sys, fastapi, uvicorn; print(sys.version.split()[0]); print(f"fastapi={fastapi.__version__}"); print(f"uvicorn={uvicorn.__version__}")'
text
3.13.11
fastapi=0.141.1
uvicorn=0.52.1

这一步通过,说明解释器、框架和服务器依赖已经对齐;如果此时失败,问题还在环境层,不必急着检查浏览器。


启动 Uvicorn 并观察一次完整请求

在 main.py 所在目录执行:

bash
uv run uvicorn main:app --reload --host 127.0.0.1 --port 8000
text
INFO:     Will watch for changes in these directories: ['/private/tmp/fastapi-ch02.iZzmPF']
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO:     Started reloader process using WatchFiles
INFO:     Started server process
INFO:     Waiting for application startup.
INFO:     Application startup complete.

启动命令中最容易看错的是 main:app。冒号左边 main 是模块名,对应 main.py;右边 app 是模块里的变量名,对应 app = FastAPI(...)。它表达的其实就是“从 main 模块导入 app 对象”。

--reload 会观察代码文件,保存修改后重启开发进程。它适合本地开发,不是生产环境增加并发能力的开关。--host 127.0.0.1 只监听本机回环地址;--port 8000 指定端口。

一次请求从浏览器进入服务器并生成响应与文档

保持服务器运行,另开一个终端请求根路径:

bash
curl -sS http://127.0.0.1:8000/
json
{"message":"FastAPI 已经运行","docs":"/docs"}

再请求带路径参数和查询参数的路由:

bash
curl -sS "http://127.0.0.1:8000/tasks/7?detail=true"
json
{"task_id":7,"detail":true}

这两次响应说明路由匹配、参数转换和 JSON 序列化都已经工作。此时打开 http://127.0.0.1:8000/docs,会看到可直接发请求的 Swagger UI;打开 http://127.0.0.1:8000/redoc,会看到另一套阅读型文档;http://127.0.0.1:8000/openapi.json 则提供生成这些页面所依据的 OpenAPI 描述。

检查文档和描述端点的状态:

bash
curl -sS -o /dev/null -w "docs_status=%{http_code}\n" http://127.0.0.1:8000/docs
curl -sS -o /dev/null -w "openapi_status=%{http_code}\n" http://127.0.0.1:8000/openapi.json
text
docs_status=200
openapi_status=200

接口文档不是另一份需要手工同步的文件。FastAPI 会读取路由、参数类型和应用元数据,生成 OpenAPI 描述,再由文档界面展示出来。你把 task_id: int 改成其他类型,描述与校验行为会一起变化。

到这里,开发环境已经真的连成一条线:包管理器准备依赖,Uvicorn 监听端口,FastAPI 匹配路由并转换数据,函数返回结果,OpenAPI 描述又驱动交互文档。以后增加接口,仍然是在这条链路上扩展。

停止开发服务器时,在运行它的终端按 Ctrl+C。正常退出会显示应用关闭和进程结束信息,不需要另外查找并强制杀死进程。


启动失败时按现象定位

环境问题让人烦躁,往往是因为我们盯着整条链路一起猜。更有效的办法是先看错误发生在哪一层:终端是否找到命令、Python 是否找到模块、Uvicorn 是否导入应用、端口是否能绑定。

开发服务器启动错误的分层排查路线

找不到 uvicorn 或 fastapi 命令

常见提示是 command not found 或“无法将该项识别为命令”。先不要全局安装。使用项目工具显式运行:

bash
uv run uvicorn main:app --reload

使用 pip 路线时,先激活 .venv,再执行:

bash
python -m uvicorn main:app --reload

python -m uvicorn 绕过了 shell 对独立 uvicorn 可执行文件的查找,能明确使用当前 Python 中安装的模块。

无法导入 main 模块

如果写成不存在的模块:

bash
uv run uvicorn missing:app --host 127.0.0.1 --port 8033
text
ERROR:    Error loading ASGI app. Could not import module "missing".

依次检查:当前目录是否真的有 main.py,命令是否从项目根目录执行,文件名是否写错,代码包是否需要完整导入路径。假设应用移到 app/main.py,而 app 是 Python 包,导入串通常要改成 app.main:app。

模块存在,但找不到 app

右侧变量名写错时会得到另一种错误:

bash
uv run uvicorn main:nope --host 127.0.0.1 --port 8033
text
ERROR:    Error loading ASGI app. Attribute "nope" not found in module "main".

这说明 main.py 已经成功导入,问题缩小到对象名。检查文件里究竟写的是 app = FastAPI()、application = FastAPI(),还是一个返回应用的工厂函数,然后让冒号右侧与之对应。

地址已经被占用

同一地址和端口上已经有服务器时,再启动一个进程会失败:

bash
uv run uvicorn main:app --host 127.0.0.1 --port 8000
text
ERROR:    [Errno 48] error while attempting to bind on address ('127.0.0.1', 8000): address already in use

回到旧服务器的终端按 Ctrl+C,或者在确认旧进程仍需保留时换一个端口:

bash
uv run uvicorn main:app --reload --port 8001

修改代码后页面没有变化

先确认启动命令包含 --reload,再看 Uvicorn 输出的监听目录是否包含源码。如果你在容器、网络磁盘或某些子系统里开发,文件变化事件可能无法按默认方式传递,这时需要针对运行环境调整文件监听方式。不要用浏览器反复刷新来掩盖服务器根本没有重启的问题。

安装成功,运行时仍提示缺包

连续执行下面三条:

bash
python -c "import sys; print(sys.executable)"
python -m pip --version
python -m pip show fastapi

解释器路径、pip 所在路径和 FastAPI 的安装位置应该落在同一个 .venv 下。只要三者不在一起,就说明“安装依赖”和“运行项目”使用了不同环境。

不要在看到导入错误后立刻使用管理员权限全局安装。它可能暂时让错误消失,却把依赖装进另一套解释器,下一次打开终端、切换编辑器或部署时问题还会回来。


锁定依赖,让环境可以重新得到

“我的环境现在能跑”和“任何人都能重建它”是两件事。.venv 证明前者;依赖声明、锁定文件和重建检查才证明后者。

从依赖声明到另一台电脑成功运行的复现闭环

使用 uv 的复现流程

pyproject.toml 描述项目接受的版本范围,uv.lock 保存解析出的精确版本和包文件校验信息。锁定文件应该提交到版本控制,.venv 不应该提交。

检查锁定文件是否仍与项目声明一致:

bash
uv lock --check
text
Resolved 45 packages in 3ms

同步项目环境:

bash
uv sync
text
Resolved 45 packages in 3ms
Audited 43 packages in 0.92ms

在持续集成或部署流程中,如果不允许命令悄悄更新锁定结果,可以使用:

bash
uv sync --locked

当 pyproject.toml 与 uv.lock 不一致时,这条命令会失败,提醒你先在开发阶段明确更新锁定文件。这样部署拿到的是已经审查过的解析结果,不是现场重新选择一套新版本。

需要升级时也不要顺手删掉锁定文件。升级全部依赖可以显式执行 uv lock --upgrade;只升级一个包则使用 uv lock --upgrade-package 包名。升级后运行接口和测试,再提交新的锁定结果。

使用 pip 的复现流程

如果采用 pip 路线,可以把人工维护的直接依赖与完整锁定结果分开。requirements.in 表达“项目主动需要什么”,requirements.txt 表达“这次验证使用了哪些精确版本”。至少要确保生成锁定结果的环境只包含本项目依赖。

在一套全新环境里验证,而不是继续相信已经用很久的旧环境:

bash
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -r requirements.txt
python -c "import fastapi, uvicorn; print(fastapi.__version__, uvicorn.__version__)"

能在空环境中完成安装、导入和启动,才说明依赖文件足够复现。若安装依赖必须依靠某个人电脑上残留的包,锁定文件仍是不完整的。

编辑器也要选择同一个解释器

终端跑通后,编辑器仍可能标红 from fastapi import FastAPI。这通常不是包没安装,而是编辑器选择了系统 Python。把项目解释器设置为 .venv/bin/python;Windows 对应 .venv\Scripts\python.exe。编辑器、终端、测试命令和部署入口指向同一套环境,类型提示与运行结果才会一致。


用一张检查表结束环境搭建

现在不要再增加工具,按顺序确认这些结果:

  1. python 或 uv run python 显示的是项目选定的 Python 版本。
  2. 项目使用独立 .venv,并且 .venv/ 已加入忽略文件。
  3. FastAPI 和 Uvicorn 可以从项目环境中导入。
  4. main.py 中存在可导入的 app 对象。
  5. Uvicorn 能在本机端口启动,根路径返回预期 JSON。
  6. /docs 与 /openapi.json 都返回成功状态。
  7. 依赖声明和锁定文件已经保存,空环境可以据此重建。

如果这七项都成立,你得到的就不只是“今天碰巧能运行”的示例,而是一份可以继续写路由、加模型、接数据库并交给别人复现的项目起点。

1
终端能运行项目,但编辑器仍提示找不到 FastAPI,最先应该检查什么?
2
为了让 uv 管理的项目可复现,通常应该提交哪些文件?
上一章FastAPI 和 RESTful API 概览下一章FastAPI 核心特性