在实际项目中,很多开发者对FastAPI项目结构感到迷茫——代码全堆在main.py里,或者模块间互相导入绕成死结。其实,一套清晰的分层模式能让项目跑得更稳、改得更爽。下面这套拆分方案经过了多个中大型项目的验证,直说干货。
一、最简分层逻辑(核心 4 层)
先捋清楚四个层次各自该干什么:
- 路由层 routers:只负责接收请求、参数校验、返回响应,业务逻辑一个字都不写。
- 业务层 services:核心业务逻辑全放这儿,调用数据库、调第三方接口,都在这一层搞定。
- 数据层 db/models/crud:模型定义、数据库增删改查,数据怎么存怎么取归它管。
- 公共层 core/schemas/utils:配置、Pydantic 模型、工具函数、全局依赖,所有公用零件放这儿。
二、完整目录结构(推荐)
直接上经过验证的推荐结构,照着搭就行:
fastapi_project/
├── main.py # 程序入口,注册路由、启动app
├── core/ # 核心配置
│ ├── config.py # 全局配置(数据库地址、密钥、跨域)
│ ├── security.py # JWT、密码加密、权限校验
│ └── dependencies.py # 全局依赖(登录鉴权、分页、日志)
├── db/ # 数据库相关
│ ├── base.py # 数据库基类、会话创建
│ ├── session.py # 数据库连接、get_db依赖
│ └── models/ # SQLAlchemy ORM模型
│ ├── user.py
│ └── goods.py
├── crud/ # 数据库操作封装(增删改查)
│ ├── base.py # 通用CRUD父类
│ ├── user_crud.py
│ └── goods_crud.py
├── schemas/ # Pydantic 序列化/校验模型
│ ├── user.py # 用户入参、出参模型
│ └── goods.py
├── routers/ # 接口路由(按模块拆分)
│ ├── __init__.py # 统一汇总所有路由
│ ├── user.py # 用户模块接口
│ └── goods.py # 商品模块接口
├── services/ # 业务逻辑层(复杂逻辑放这里)
│ ├── user_service.py
│ └── order_service.py
├── utils/ # 通用工具
│ ├── logger.py
│ ├── file.py
│ └── time.py
├── static/ # 静态文件
├── tests/ # 单元测试
└── requirements.txt
三、各层作用与代码示例
1. main.py 入口文件
main.py只做一件事:组装和启动。接口逻辑一概不碰,干净利落:
from fastapi import FastAPI
from core.config import settings
from core.dependencies import cors_middleware
from routers import api_router
app = FastAPI(title=settings.PROJECT_NAME)
# 跨域
app.add_middleware(cors_middleware)
# 挂载所有路由
app.include_router(api_router, prefix="/api/v1")
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)
2. routers 路由层(只处理请求转发)
路由层就是个“接线员”,收到请求后转给service,完事返回结果。以用户模块为例:
# routers/user.py
from fastapi import APIRouter, Depends
from schemas.user import UserCreate, UserResp
from services.user_service import create_user
from db.session import get_db
from sqlalchemy.orm import Session
router = APIRouter(prefix="/user", tags=["用户模块"])
@router.post("/add", response_model=UserResp)
def add_user(user_in: UserCreate, db: Session = Depends(get_db)):
# 只调用service,不写业务
return create_user(db=db, user_in=user_in)
所有路由模块统一在 routers/__init__.py 里聚合,方便统一挂载:
# routers/__init__.py
from fastapi import APIRouter
from .user import router as user_router
from .goods import router as goods_router
api_router = APIRouter()
api_router.include_router(user_router)
api_router.include_router(goods_router)
3. services 业务层(核心逻辑)
所有真正干活的代码放到service里——密码加密、重复校验、联动其他表,都在这里完成:
# services/user_service.py
from sqlalchemy.orm import Session
from schemas.user import UserCreate
from crud.user_crud import user_crud
from core.security import hash_password
def create_user(db: Session, user_in: UserCreate):
# 业务逻辑:密码加密、重复校验、联动其他表
user_in.password = hash_password(user_in.password)
return user_crud.create(db, obj_in=user_in)
4. crud 数据操作层(纯数据库操作)
CRUD层只和数据库打交道,不掺和任何业务判断。一个通用的CRUD基类 + 具体实体的增删改查:
# crud/user_crud.py
from crud.base import CRUDBase
from db.models.user import User
from schemas.user import UserCreate, UserUpdate
class CRUDUser(CRUDBase[User, UserCreate, UserUpdate]):
def get_by_phone(self, db: Session, phone: str):
return db.query(User).filter(User.phone == phone).first()
user_crud = CRUDUser(User)
5. schemas 数据校验 / 序列化
入参、出参、更新模型分开定义,用Pydantic做校验,前端交互和数据库模型彻底解耦。比如 UserCreate、UserResp、UserUpdate 各司其职。
6. db 数据库层
- models:SQLAlchemy ORM映射,定义表结构
- session:数据库连接池、会话依赖
get_db - base:公共模型基类(id、创建时间、更新时间)
7. core 全局核心
- config:读取.env环境变量,配置统一管理
- security:JWT签发、密码加密、token校验
- dependencies:全局依赖,如登录校验、分页、统一异常捕获
四、两种拆分方案选择
方案 1:按模块拆分(推荐,中大型项目)
结构上 routers/user、services/user、crud/user、schemas/user 各成一派。好处是模块清晰,多人协作互不干扰,特别适合后台管理、接口平台这类复杂业务。
方案 2:按功能分层(小型 demo)
不拆分模块,只分 core / db / routers 三层,所有逻辑写单个文件。适合简单工具接口,一梭子干完即走。
五、分层调用规范(单向依赖,禁止反向导入)
请求流向必须严格遵循:main → routers → services → crud → db.models
下面三条红线绝对不能碰:
- crud 禁止导入 service
- router 不能直接操作 crud
- model 不能导入 schema
一旦打破单向依赖,项目就会变成意大利面——改一处崩一片。
六、扩展补充
- 异常统一处理:在
core/exceptions.py里全局捕获异常,统一返回格式,前端对接省心很多。 - 中间件:
core/middleware.py放请求日志、耗时统计,想加什么拦截逻辑都方便。 - 第三方接口:新建
clients/文件夹,专门放支付SDK、OSS、信息等外部调用,别塞进service里。 - 定时任务:单独
tasks/目录,用APScheduler跑,绝不和接口代码耦合。
