Skip to content

第 06 章 数据校验 Schema ​

学习目标 ​

学完本章,你应该能:

  1. 理解 Schema 的作用,以及它和 Model 的区别
  2. 掌握 fba 中 Schema 的命名规范
  3. 能定义请求入参和响应出参模型

一、Schema 是什么 ​

Schema 是数据的"模板",用来定义和校验数据的形状。它基于 Pydantic 库实现。

Pydantic:Python 最流行的数据校验库,能自动验证数据类型、做格式转换、生成文档。fba 用的是 Pydantic v2。

Schema vs Model 的区别 ​

这是新手最容易混淆的点:

对比项Model(第 05 章)Schema(本章)
对应数据库表结构接口的输入/输出数据
用途操作数据库校验请求、格式化响应
库SQLAlchemyPydantic
变化跟表结构走跟接口需求走

一句话:Model 管"数据存进数据库的样子",Schema 管"数据进出接口的样子"。同一个 Model 可以对应多个 Schema(新增要这些字段,查询要那些字段)。

Model 与 Schema 的配合关系 ​

二、fba 的 Schema 基类 ​

fba 对 Schema 做了大量定制,核心在 backend/common/schema.py 的 SchemaBase 类:

python
class SchemaBase(BaseModel):
    model_config = ConfigDict(
        populate_by_name=True,   # 允许用原始字段名或别名赋值
        alias_generator=to_camel,  # 自动把字段名转成小驼峰
        use_enum_values=True,
    )

关键点:

  • 驼峰返回:Python 习惯用下划线命名(user_name),前端习惯用小驼峰(userName)。SchemaBase 自动做转换,返回给前端的数据会自动变成小驼峰。
  • 所有自定义 Schema 都继承 SchemaBase。

小驼峰命名:第一个单词小写,后面单词首字母大写,如 userName、createdTime。

驼峰转换示意 ​

三、类命名规范 ​

fba 对 Schema 类命名有严格规范,强烈建议遵守(AI 生成代码也遵循此规范):

类名用途
XxxSchemaBase基础 Schema(公共字段)
XxxParam接口入参
CreateXxxParam新增入参
UpdateXxxParam更新入参
DeleteXxxParam批量删除入参
GetXxxDetail查询详情出参
GetXxxWithJoinDetail查询详情(带 join)出参
GetXxxWithRelationDetail查询详情(带关系)出参
GetXxxTree查询树形结构出参

记忆技巧:Create/Update/Delete/Get 前缀 + 业务名 + Param/Detail 后缀。

Schema 家族关系图 ​

四、Field 定义规范 ​

fba 建议:

  1. 不建议用 ... 表示必填(Pydantic 的省略号写法),参考官方文档用更明确的方式
  2. 建议为所有字段加 description,这对 API 文档非常有用

示例:

python
from pydantic import Field

class CreateUserParam(SchemaBase):
    username: str = Field(description='用户名')
    password: str = Field(description='密码')
    nickname: str | None = Field(default=None, description='昵称')

Field:Pydantic 提供的字段描述函数,可设置默认值、描述、校验规则等。

五、完整示例:用户模块的 Schema ​

结合命名规范,一个用户模块的 Schema 可能长这样:

python
class UserSchemaBase(SchemaBase):
    """用户基础字段"""
    username: str = Field(description='用户名')
    nickname: str | None = Field(default=None, description='昵称')


class CreateUserParam(UserSchemaBase):
    """新增用户入参"""
    password: str = Field(description='密码')


class UpdateUserParam(SchemaBase):
    """更新用户入参(字段都可选)"""
    nickname: str | None = Field(default=None, description='昵称')


class GetUserDetail(UserSchemaBase):
    """查询用户详情出参"""
    id: int = Field(description='用户ID')
    created_time: datetime = Field(description='创建时间')

注意:

  • 新增和更新的入参字段不同(新增要密码,更新可能只要昵称)
  • 出参(Detail)通常比入参多出 id、时间戳等系统字段

六、Schema 在接口中的使用 ​

Schema 最终用在 API 层的路由里,FastAPI 会自动用它校验数据:

python
@router.post('/user', summary='创建用户')
async def create_user(obj: CreateUserParam) -> ResponseModel:
    ...

当请求进来时,FastAPI 会:

  1. 自动校验请求体是否符合 CreateUserParam
  2. 类型不匹配或缺少必填字段时,自动返回 422 错误
  3. 校验通过后,把数据以 CreateUserParam 对象传入函数

数据校验流程 ​

七、常见疑问 ​

Q1:为什么更新入参字段都要设为可选? 因为更新接口通常只更新部分字段(比如只改昵称不改密码),设为可选才能"传哪个改哪个"。

Q2:同一个 Model 为什么要多个 Schema? 因为"新增"和"查询"需要的字段不同:新增需要密码,查询返回的是 id + 时间戳,不该把密码暴露出去。分多个 Schema 能精确控制每个接口的字段。

本章小结 ​

关键要点回顾:

  • Schema 基于 Pydantic v2,用于校验接口输入/输出数据
  • Model 管数据库,Schema 管接口,两者不要混淆
  • 命名规范:Create/Update/Delete/Get 前缀 + Param/Detail 后缀
  • 继承 SchemaBase 自动获得驼峰转换
  • 字段记得写 description,方便生成 API 文档

下一步: 数据定义好了(Model + Schema),第 07 章学习如何定义路由(Router),把接口暴露出去。


对应官方文档:schema(backend/reference/schema.html)