Skip to content

31. FastAPI 依赖注入介绍 ​

依赖注入就是“需要什么,声明什么” ​

多个接口都要分页参数、当前用户或数据库 Session,逐个手工调用会重复。依赖注入让路由声明需要的资源,框架负责解析输入、执行依赖,并把结果交给路由。

Depends(get_pagination) 传的是函数本身,不能写成 Depends(get_pagination()),否则导入时就执行了函数。

一个最容易理解的例子 ​

python
from typing import Annotated
from fastapi import Depends, FastAPI, Query

app = FastAPI()

def get_pagination(
    page: Annotated[int, Query(ge=1)] = 1,
    size: Annotated[int, Query(ge=1, le=100)] = 20,
):
    return {"page": page, "size": size, "offset": (page - 1) * size}

PaginationDep = Annotated[dict, Depends(get_pagination)]

@app.get("/users")
def users(pagination: PaginationDep):
    return {"resource": "users", **pagination}

@app.get("/products")
def products(pagination: PaginationDep):
    return {"resource": "products", **pagination}

保存为 main.py,运行 uv run uvicorn main:app --reload。两个接口都支持 page 和 size,且在 /docs 中显示验证规则。/users?page=2&size=5 返回 offset=5;传 size=0 则在执行业务前失败。

普通调用与依赖调用的区别 ​

依赖函数里也能声明 Query、Header 和其他 Depends,框架会继续解析;普通调用 get_pagination() 只是 Python 调用,不会启动这套解析流程。同理,在命令行直接调用路由函数不会自动注入真实用户或 Session。

资源依赖使用 yield ​

数据库 Session 可以在 yield 前创建,在退出阶段关闭。第 20 篇 get_db 就是这个模式。yield 的值注入路由,finally 负责清理;异常发生后也要正确传播,不能吞掉异常后伪装成功。

当前版本中,yield 依赖默认按请求作用域清理,通常在响应发送后;若依赖只用于函数执行阶段,可根据版本支持使用 Depends(..., scope="function") 提前结束。流式输出可能仍需资源,应按实际生命周期选择。

事务提交应在业务成功返回前完成,不依赖清理阶段偷偷提交。后台任务需要自己的 Session,不能借用马上要关闭的请求资源。

缓存与测试 ​

同一请求中相同依赖通常复用已计算结果,这不是全局缓存。use_cache=False 可要求重新执行某次依赖;不适合滥用来解决设计问题。

测试可通过 app.dependency_overrides[原依赖] = 替代依赖 替换外部资源,结束后清空,避免影响其他测试。依赖覆盖不会自动模拟事务、权限等业务语义,需要按场景提供合理替代。

练习:让分页依赖同时返回排序方式,再被两个路由复用;打印依赖执行次数,观察每次请求的生命周期。