FastAPI 项目布局详解
轻量多文件
适用于小型服务、10 个接口左右、1-2 个业务领域:
my_app/
├── __init__.py
├── main.py # FastAPI app 入口 + 路由注册
├── router.py # 路由(接口多时可拆成 router_xxx.py)
├── models.py # SQLModel 数据库模型
├── schemas.py # Pydantic 入参/出参
├── service.py # 业务逻辑
├── deps.py # 依赖注入
└── config.py # 配置
作为一个 Python 包组织,包内用相对导入 from .models import Xxx,外部通过 pip install -e . 安装后用绝对导入。
main.py 示例:
from contextlib import asynccontextmanager
from fastapi import FastAPI
from .router import router
@asynccontextmanager
async def lifespan(app: FastAPI):
yield
app = FastAPI(lifespan=lifespan)
app.include_router(router)
领域分包
适用于多业务领域、团队协作、长期维护的大项目:
src/
├── main.py # 入口:创建 app,注册所有 router
├── config.py # 全局配置(DATABASE_URL, REDIS_URL 等)
├── database.py # 数据库连接、Session 工厂
├── models.py # 全局基础模型(Base, 时间戳 mixin)
├── exceptions.py # 全局异常处理器
├── pagination.py # 通用分页
│
├── auth/ # ─── 认证领域 ───
│ ├── __init__.py
│ ├── router.py # 端点定义
│ ├── schemas.py # Pydantic 入参/出参
│ ├── models.py # 数据库模型
│ ├── service.py # 业务逻辑
│ ├── dependencies.py # 依赖注入(如 get_current_user)
│ ├── constants.py # 常量和错误码
│ ├── config.py # 模块专属环境变量
│ ├── utils.py # 工具函数(如 hash_password)
│ └── exceptions.py # 模块专属异常(如 InvalidCredentials)
│
├── posts/ # ─── 帖子领域(同样的 9 个文件)───
│ └── ...
└── users/ # ─── 用户领域(同样的 9 个文件)───
└── ...
9 个文件各自的职责
| 文件 | 职责 | 示例 |
|---|---|---|
| router.py | 定义 HTTP 端点,只做接/返,不写业务 | @router.get("/{post_id}") |
| schemas.py | Pydantic 模型,定义入参出参的形状 | PostCreate, PostResponse |
| models.py | SQLModel/SQLAlchemy 数据库表定义 | class Post(Base, table=True) |
| service.py | 业务逻辑,查库、计算、组合数据 | create(), get_by_id() |
| dependencies.py | 依赖注入,做请求级校验 | valid_post_id(), valid_owned_post() |
| constants.py | 常量、枚举、错误码 | ErrorCode.POST_NOT_FOUND |
| config.py | 模块专属的 BaseSettings | PostsConfig(MAX_POSTS_PER_USER=100) |
| utils.py | 非业务工具函数 | slugify(), truncate() |
| exceptions.py | 模块专属异常类 | PostNotFound(HTTPException) |
关键规则
依赖方向单向,绝不反向:
schemas / constants / config / utils / exceptions 是底层工具,任何层都可以用,但它们不依赖上面的层。跨模块用绝对导入 + 别名:
main.py 只做注册: