对于基于FastAPI框架的web项目而言,我们总能在app文件里看见models / schemas / services / 视图函数(routers / controllers)这样不同名字的文件夹, 这是FastAPI + SQLAlchemy + Pydantic 的典型目录结构。
下面用 FastAPI + SQLAlchemy + Pydantic 的典型目录结构来说明四个层次——models / schemas / services / 视图函数(routers / controllers)——各自职责与数据流向。逻辑同样适用于 Django、Flask‐SQLAlchemy、NestJS 等分层思想,只是命名略有不同。
1. models(持久化/数据库层)
| 关键点 | 说明 |
|---|---|
| 作用 | 映射数据库表,负责 持久化:增删改查(ORM 操作)、表结构定义。 |
| 技术 | SQLAlchemy DeclarativeBase、Django ORM、GORM 等。 |
| 只关心 | 字段类型、索引、外键、关系映射(relationship)、事务。 |
| 不做 | 数据校验(业务层面)、序列化给前端等。 |
class User(Base): # SQLAlchemy
__tablename__ = "users"
id = Column(Integer, primary_key=True, index=True)
email = Column(String, unique=True, index=True)
hashed_password = Column(String)
is_active = Column(Boolean, default=True)
2. schemas(Pydantic 模型/序列化层)
| 关键点 | 说明 |
|---|---|
| 作用 | 输入输出的契约:请求体反序列化、响应体序列化、字段校验;与数据库解耦。 |
| 技术 | Pydantic BaseModel、Marshmallow、DRF Serializer。 |
| 只关心 | 字段格式、校验规则、默认值、嵌套模型、OpenAPI 文档。 |
| 不做 | 直接操作数据库、业务计算。 |
class UserCreate(BaseModel):
email: EmailStr
password: constr(min_length=8) # 仅限创建时出现
class UserOut(BaseModel):
id: int
email: EmailStr
is_active: bool
优点:
-
安全:不把数据库的敏感字段(如
hashed_password)暴露给前端。 -
解耦:数据库换成 MongoDB,只改 models 和 services,schema 不变。
-
文档:Pydantic → FastAPI 自动生成 Swagger/OpenAPI。
3. services(业务逻辑层 / service layer)
| 关键点 | 说明 |
|---|---|
| 作用 | 业务规则 + 复用:聚合多个 model、封装事务、第三方调用、复杂计算。 |
| 技术 | 普通 Python 模块 / 类,偶尔搭配 DDD 的 Domain Service。 |
| 只关心 | 业务流程与边界:如“注册用户”= 判重 → Hash 密码 → 写库 → 发送邮件。 |
| 不做 | HTTP 解析 / 响应、页面渲染。 |
class UserService:
@staticmethod
def create_user(db: Session, obj_in: UserCreate) -> User:
if db.query(User).filter(User.email == obj_in.email).first():
raise DuplicateEmailError
hashed = hash_password(obj_in.password)
user = User(email=obj_in.email, hashed_password=hashed)
db.add(user); db.commit(); db.refresh(user)
return user
4. 视图函数 / controllers / routers(接口层)
| 关键点 | 说明 |
|---|---|
| 作用 | HTTP → 业务 的粘合剂:解析请求、调用 service、返回响应。 |
| 技术 | FastAPI APIRouter, Flask view function, Django ViewSet。 |
| 只关心 | 路由、权限、依赖注入、HTTP 状态码、错误转换。 |
| 不做 | ORM 细节、复杂业务;这些交给 service。 |
router = APIRouter()
@router.post("/users/", response_model=UserOut, status_code=201)
def create_user(
user_in: UserCreate,
db: Session = Depends(get_db),
):
user = UserService.create_user(db, user_in)
return user # Pydantic 自动序列化为 JSON
层与层之间如何协作?
HTTP 请求 数据流 →
┌────────────┐
│ 前端/客户端 │
└─────┬──────┘
│ JSON (UserCreate)
┌─────▼──────┐
│ 视图函数 │ 依赖注入 / 路由匹配
└─────┬──────┘
│ Pydantic 校验完的 UserCreate
┌─────▼──────┐
│ Service │ 业务流程、跨模型操作
└─────┬──────┘
│ ORM Entity / Query
┌─────▼──────┐
│ Models │ SQLAlchemy CRUD
└─────┬──────┘
│ DB Driver
┌─────▼──────┐
│ 数据库 │
└────────────┘
-
视图函数 把 JSON →
UserCreate(schema),然后交给 services。 -
services 操作 models(ORM),返回
User对象。 -
视图函数再用
UserOut(schema) 把 ORM 对象 → JSON,返回给客户端。
为什么要分层?
| 目的 | 带来的好处 |
|---|---|
| 单一职责 | 每层只管一件事,逻辑更清晰,易维护。 |
| 可测试性 | service 层可写纯单元测试,视图函数只测路由/权限。 |
| 解耦/复用 | 改数据库、不走 HTTP 改成 CLI,service 层几乎不动。 |
| 安全 | schema 隔离敏感字段,防止“过度暴露”。 |
790

被折叠的 条评论
为什么被折叠?



