文章目录
-
- 前言
- 一、阶段学习目标
- 二、什么是依赖注入?核心优势
-
- [2\.1 概念](#2.1 概念)
- [2\.2 四大核心优势](#2.2 四大核心优势)
- [三、基础 1:普通函数依赖(最常用)](#三、基础 1:普通函数依赖(最常用))
-
- [3\.1 基础分页公共依赖](#3.1 基础分页公共依赖)
- [3\.2 无返回值依赖(仅做校验)](#3.2 无返回值依赖(仅做校验))
- [四、基础 2:类依赖(带参数通用校验)](#四、基础 2:类依赖(带参数通用校验))
- [五、核心重点:yield 生成器依赖(资源管理神器)](#五、核心重点:yield 生成器依赖(资源管理神器))
-
- [5\.1 yield 与 return 本质区别](#5.1 yield 与 return 本质区别)
- [5\.2 生产标准:SQLModel 数据库会话依赖(重中之重)](#5.2 生产标准:SQLModel 数据库会话依赖(重中之重))
- 六、高阶:嵌套多层依赖(鉴权标准链路)
- 七、四级依赖作用域(项目分层必备)
-
- [7\.1 路由组全局依赖(模块化最佳实践)](#7.1 路由组全局依赖(模块化最佳实践))
- [7\.2 全局 App 依赖(全站生效)](#7.2 全局 App 依赖(全站生效))
- [7\.3 接口装饰器依赖(无需接收返回值)](#7.3 接口装饰器依赖(无需接收返回值))
- [八、综合实战:数据库 \+ 登录鉴权完整案例](#八、综合实战:数据库 + 登录鉴权完整案例)
- [九、依赖缓存机制 \& 异步说明](#九、依赖缓存机制 & 异步说明)
- 十、新手高频避坑指南
- 十一、阶段核心总结
前言
经过前三阶段学习,我们掌握基础接口、Pydantic 请求 / 响应、表单文件、全局异常,但写项目时会遇到大量重复代码:
-
每个接口都要写分页参数解析;
-
每个接口重复写数据库会话获取、关闭;
-
每个需要登录的接口重复解析 Token、查询用户;
-
权限校验、日志打印、限流逻辑到处复制粘贴。
这些重复逻辑靠复制维护极其繁琐,而依赖注入 Depends 是 FastAPI 核心灵魂 ,专门解决代码复用、逻辑解耦、资源自动管理。
本阶段 1 天学完,覆盖函数 / 类 /yield 资源依赖、嵌套多层依赖、四级作用域(接口 / 路由 / 全局)、登录鉴权实战,学完就能写出标准化分层后端项目,完美搭配前面学的 SQLModel 数据库。
一、阶段学习目标
-
理解依赖注入核心设计思想:解耦、复用、自动生命周期管理;
-
掌握基础函数依赖,封装分页、公共查询参数;
-
学会类依赖,处理带参数通用校验逻辑;
-
吃透
yield生成器依赖(数据库会话、文件连接必备); -
掌握嵌套多层依赖(鉴权链路:解析 Token→查用户→校验角色);
-
四级依赖作用域:单接口、APIRouter 路由组、全局 App 依赖;
-
完整实战:数据库会话依赖 + 登录用户鉴权依赖;
-
理清依赖缓存机制、异步依赖执行规则、高频避坑点。
二、什么是依赖注入?核心优势
2.1 概念
依赖(Dependable) :任意可调用对象(函数 / 类),封装一段可复用逻辑 ;
Depends():告诉框架自动执行该逻辑,将返回值注入接口参数,无需手动调用。
2.2 四大核心优势
-
代码复用:分页、鉴权、DB 会话写一次,所有接口直接引用;
-
逻辑解耦:业务接口只处理核心业务,校验 / 资源逻辑抽离;
-
自动生命周期:
yield实现资源自动创建 + 释放(数据库自动关闭会话); -
易测试:单元测试可替换 Mock 依赖,不用侵入业务代码。
三、基础 1:普通函数依赖(最常用)
3.1 基础分页公共依赖
多列表接口共用分页参数,无需每个接口重复定义 page、page_size
python
from fastapi import FastAPI, Depends
from typing import Annotated
app = FastAPI(title="函数依赖演示")
# 公共分页依赖函数
def get_page_params(page: int = 1, page_size: int = 10):
"""统一分页参数校验,限制每页最大50条"""
if page_size > 50:
page_size = 50
offset = (page - 1) * page_size
return {"page": page, "page_size": page_size, "offset": offset}
# 商品列表接口复用分页
# 注入分页参数依赖:
# - Annotated 用于为参数附加元数据(类型提示)
# - dict 表示该参数最终会被解析为字典格式
# - Depends(get_page_params) 表示该参数的值由 get_page_params 函数提供(如提取 query 中的 page、page_size 等)
@app.get("/goods")
def list_goods(page_info: Annotated[dict, Depends(get_page_params)]):
return {"分页信息": page_info, "数据": []}
# 用户列表复用同一套分页
@app.get("/users")
def list_users(page_info: dict = Depends(get_page_params)):
return {"分页信息": page_info, "用户数据": []}
Annotated 是 Python3.10 + 标准写法,类型提示更清晰,推荐统一使用。
3.2 无返回值依赖(仅做校验)
只执行校验逻辑,不需要返回值,参数名用_接收:
python
from fastapi import Depends, HTTPException
def check_maintain():
"""全局维护校验依赖"""
is_maintain = False
if is_maintain:
raise HTTPException(status_code=503, detail="系统维护中,暂时无法访问")
@app.get("/notice")
def get_notice(_ = Depends(check_maintain)):
return {"msg": "公告正常展示"}
四、基础 2:类依赖(带参数通用校验)
函数无法传参时,使用类作为依赖,实例化时传入配置参数,适合限流、权限校验模板。
python
from fastapi import FastAPI, Depends, HTTPException
app = FastAPI()
# 修复后的限流依赖类
class RateLimitCheck:
def __init__(self, max_times: int):
self.max_times = max_times
def __call__(self):
# 模拟限流逻辑
current_req = 20
if current_req > self.max_times:
raise HTTPException(status_code=429, detail="请求过于频繁")
# 普通接口,最多允许10次请求(正确写法1:dependencies列表)
@app.get("/index", dependencies=[Depends(RateLimitCheck(max_times=10))])
def index():
return {"data": "首页内容"}
# 管理员接口宽松限流,最多100次(正确写法2:函数形参接收)
@app.get("/admin/dashboard")
def admin_dash(_ = Depends(RateLimitCheck(max_times=100))):
return {"data": "管理后台数据"}
原理:类实现__call__方法,实例变成可调用对象,FastAPI 自动执行。
五、核心重点:yield 生成器依赖(资源管理神器)
5.1 yield 与 return 本质区别
-
return:函数执行结束,无法执行收尾代码; -
yield:先执行前面逻辑,返回资源给接口;接口执行完毕后自动执行 yield 后的代码,适合数据库、文件、连接自动释放。
5.2 生产标准:SQLModel 数据库会话依赖(重中之重)
python
from sqlmodel import create_engine, Session
from fastapi import Depends
from typing import Annotated
# 数据库引擎(沿用之前SQLModel工程代码)
DB_URL = "sqlite:///./test.db"
engine = create_engine(DB_URL, echo=False)
# 标准DB会话依赖
def get_db():
# 创建会话资源
db_session = Session(engine)
try:
# 将会话注入接口,接口拿到db_session使用
yield db_session
finally:
# 无论接口正常/报错,最终都会执行关闭会话,杜绝连接泄露
db_session.close()
# 接口注入数据库会话
@app.get("/user/{uid}")
def get_user(uid: int, db: Annotated[Session, Depends(get_db)]):
user = db.get(User, uid)
return user
生产避坑:绝对不要手动创建 Session、手动 close,全部交给 yield 依赖自动管理。
六、高阶:嵌套多层依赖(鉴权标准链路)
依赖可以嵌套依赖,形成链式执行,典型场景:登录校验链路
执行顺序:解析 Token → 查询用户 → 校验用户是否激活 → 校验管理员权限
python
from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer
app = FastAPI()
# 1. 第一层依赖:从Header提取token
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/login")
# 2. 第二层依赖:解析token获取用户id
def get_token_data(token: str = Depends(oauth2_scheme)):
# 模拟JWT解析
if token != "test_token":
raise HTTPException(status.HTTP_401_UNAUTHORIZED, detail="token无效")
return {"user_id": 1, "role": "user"}
# 3. 第三层依赖:校验用户是否激活
def get_active_user(token_info = Depends(get_token_data)):
user_id = token_info["user_id"]
# 模拟查询数据库用户
user = {"id": 1, "username": "test", "is_active": True, "role": "user"}
if not user["is_active"]:
raise HTTPException(403, "账号已禁用")
return user
# 4. 第四层依赖:仅管理员可访问
def require_admin(user = Depends(get_active_user)):
if user["role"] != "admin":
raise HTTPException(403, "无管理员权限")
return user
# 普通接口:只需登录用户
@app.get("/profile")
def my_info(user = Depends(get_active_user)):
return {"用户名": user["username"]}
# 管理员接口:多层嵌套依赖
@app.get("/admin/user_list")
def admin_list(user = Depends(require_admin)):
return {"管理员操作数据": []}
执行顺序:oauth2_scheme → get_token_data → get_active_user → require_admin。
七、四级依赖作用域(项目分层必备)
依赖支持 4 个层级,作用范围由小到大:
| 作用域 | 使用位置 | 适用场景 |
|---|---|---|
| 接口参数级 | 接口函数参数 | 单接口独有依赖 |
| 路由组级 | APIRouter(dependencies=\[\]) | 某模块全部接口统一校验(用户模块、订单模块) |
| 全局应用级 | FastAPI(dependencies=\[\]) | 全站所有接口通用(系统维护、日志) |
| 接口装饰器级 | @app.get(dependencies=\[\]) | 单个接口附加校验,不占用返回参数 |
7.1 路由组全局依赖(模块化最佳实践)
python
from fastapi import APIRouter, Depends
# 用户路由组,所有接口必须登录
user_router = APIRouter(
prefix="/user",
tags=["用户管理"],
dependencies=[Depends(get_active_user)]
)
# 该接口自动注入登录校验,无需重复写Depends
@user.get("/info")
def user_info():
return {"msg": "个人信息"}
# 挂载到主app
app.include_router(user_router)
7.2 全局 App 依赖(全站生效)
python
# 所有接口都会执行系统维护校验
app = FastAPI(
title="全局依赖演示",
dependencies=[Depends(check_maintain)]
)
7.3 接口装饰器依赖(无需接收返回值)
python
# 仅执行限流,不需要接收返回值
@app.get("/goods/list", dependencies=[Depends(RateLimitCheck(20))])
def goods_list():
return []
八、综合实战:数据库 + 登录鉴权完整案例
整合 yield 数据库依赖、嵌套鉴权依赖、路由分组依赖,企业标准模板
python
from fastapi import FastAPI, Depends, HTTPException, status, APIRouter
from fastapi.security import OAuth2PasswordBearer
from sqlmodel import SQLModel, Session, create_engine
# ===================== 1. 数据库配置 =====================
DB_URL = "sqlite:///./stage4.db"
engine = create_engine(DB_URL, echo=False)
SQLModel.metadata.create_all(bind=engine)
# DB会话依赖
def get_db():
db = Session(engine)
try:
yield db
finally:
db.close()
# ===================== 2. 鉴权依赖链 =====================
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/auth/login")
def parse_token(token = Depends(oauth2_scheme)):
if token != "admin123":
raise HTTPException(status.HTTP_401_UNAUTHORIZED, "登录失效")
return {"uid": 1, "role": "admin"}
def get_current_user(db: Session = Depends(get_db), token_info = Depends(parse_token)):
# 模拟数据库查询用户
return {"id": token_info["uid"], "username": "超级管理员"}
# ===================== 3. 路由分组 =====================
# 需要登录的用户模块
user_router = APIRouter(
prefix="/api/user",
tags=["用户模块"],
dependencies=[Depends(get_current_user)]
)
@user_router("/me")
def get_my_info(user = Depends(get_current_user)):
return {"当前登录用户": user}
# 无需登录的公共路由
public_router = APIRouter(prefix="/api/public", tags=["公共接口"])
@public_router("/notice")
def get_notice():
return {"公告": "欢迎使用系统"}
# ===================== 4. 项目入口 =====================
app = FastAPI(title="依赖注入综合实战")
app.include_router(user_router)
app.include_router(public_router)
九、依赖缓存机制 & 异步说明
-
单请求缓存:同一个请求内,同一依赖只会执行一次,多次 Depends 复用不会重复执行;
-
同步 / 异步兼容:依赖函数可以 async、普通 def,FastAPI 自动适配;
-
yield 只能使用一次,一个依赖内禁止多个 yield;
-
异常穿透:依赖内抛出 HTTPException,直接终止请求,不会执行接口业务代码。
十、新手高频避坑指南
-
❌ 使用 return 做数据库会话依赖,导致会话无法自动关闭,连接池耗尽;
-
❌ 多层嵌套依赖逻辑混乱,鉴权链路建议分层拆分;
-
❌ 全局依赖配置敏感接口校验(如登录 / 注册),会导致无法访问登录页;
-
❌ 忘记 finally 关闭资源,数据库 / 文件句柄泄露;
-
❌ 大量接口重复复制分页、DB 代码,不抽离依赖;
-
✅ 数据库、文件资源统一使用 yield 生成器依赖;
-
✅ 按模块使用 APIRouter 路由级依赖,区分需要登录 / 公开接口;
-
✅ 鉴权逻辑分层封装,形成可复用依赖链。
十一、阶段核心总结
-
依赖注入核心:
Depends()自动执行复用逻辑,解耦重复代码; -
函数依赖:适合分页、简单校验等无参公共逻辑;
-
类依赖:适合可配置通用校验(限流、权限模板);
-
yield 依赖:资源创建 + 自动释放,数据库会话标准写法;
-
嵌套依赖:链式鉴权、多层逻辑分层处理;
-
四级作用域:接口 / 路由 / 装饰器 / 全局,灵活控制依赖生效范围;
-
企业标准架构:DB 会话依赖 + 登录鉴权依赖 + 路由分组依赖。