Skip to content

参数验证

使用 Pydantic v2 进行请求参数验证。所有请求体参数通过 Pydantic BaseModel 定义,FastAPI 自动解析和验证 JSON 请求体,验证失败返回标准格式错误信息。BaseForm 基类位于 src/core/base_schemas.py

基本用法

定义表单类

python
# src/modules/system/position/schemas.py
# +======================================================================
# | 模块: 岗位表单验证
# | 说明: 岗位创建/编辑/状态更新的请求数据校验
# +======================================================================

from typing import Optional

from pydantic import BaseModel, Field
from core.base_schemas import BaseForm


# ============================================================
# 岗位表单类
# ============================================================
class PositionForm(BaseForm):
    """岗位创建/编辑表单"""
    name: str = Field(..., min_length=1, max_length=150, description="岗位名称")
    status: int = Field(..., ge=1, le=2, description="岗位状态:1-在用 2-停用")
    sort: int = Field(..., ge=0, le=99999, description="岗位排序")


# ============================================================
# 设置状态表单类
# ============================================================
class PositionStatusForm(BaseModel):
    """岗位状态更新表单"""
    id: int = Field(..., gt=0, description="岗位ID")
    status: int = Field(..., ge=1, le=2, description="岗位状态:1-在用 2-停用")

端点使用

python
@router.post('/add')
@permission_required("sys:position:add")
@check_demo
async def add(request: Request, data: PositionForm):
    return await position.PositionAdd(request, data)

自动验证

FastAPI 在调用端点函数前自动完成参数验证。验证失败时返回标准格式错误:

json
{"code": 1, "data": null, "msg": "name: 字段长度不能少于1个字符"}

Field 约束

Pydantic v2 提供丰富的字段约束:

约束说明示例
min_length字符串最小长度Field(..., min_length=1)
max_length字符串最大长度Field(..., max_length=150)
ge大于等于Field(..., ge=0)
le小于等于Field(..., le=99999)
gt大于Field(..., gt=0)
lt小于Field(..., lt=100)
pattern正则匹配Field(..., pattern=r'^[a-z]+$')

自定义验证器

使用 @field_validator 装饰器添加自定义验证逻辑:

python
from pydantic import BaseModel, Field, field_validator

class UserForm(BaseForm):
    username: str = Field(..., min_length=1, max_length=50)
    email: str = Field(..., max_length=100)

    @field_validator('username')
    @classmethod
    def validate_username(cls, v):
        if not v.isalnum():
            raise ValueError('用户名只能包含字母和数字')
        return v

    @field_validator('email')
    @classmethod
    def validate_email(cls, v):
        if '@' not in v:
            raise ValueError('邮箱格式不正确')
        return v

BaseForm 基类

所有创建/编辑表单应继承 BaseForm,自动获得 id 字段和空字符串处理:

python
# src/core/base_schemas.py
# +======================================================================
# | 模块: 表单基类
# | 说明: 统一处理前端传入的空字符串 id → None 等通用校验
# +======================================================================

"""表单基类:统一处理前端传入的空字符串 id → None 等通用校验。"""

from typing import Optional

from pydantic import BaseModel, Field, field_validator


# ============================================================
# 表单基类
# ============================================================
class BaseForm(BaseModel):
    """
    表单基类

    所有创建/编辑表单应继承此类,自动获得:
        1. id 字段:Optional[int],前端传空字符串时自动转为 None
    """

    id: Optional[int] = Field(None, description="主键ID")

    @field_validator('id', mode='before')
    @classmethod
    def empty_str_to_none(cls, v):
        """前端 POST 空字符串 '' 时转为 None,避免 Pydantic 整数解析报错"""
        if v == '' or v == 'null' or v == 'undefined':
            return None
        return v

前端空字符串

前端某些组件(如 el-select)在未选择时可能传空字符串 "",BaseForm 的 empty_str_to_none 验证器会自动将其转为 None,避免整数字段解析报错。

唯一性校验

在 Pydantic 验证器中查询数据库校验唯一性:

python
from pydantic import field_validator
from core.database import get_db_session
from modules.system.position.models import Position

class PositionForm(BaseForm):
    name: str = Field(..., min_length=1, max_length=150)

    @field_validator('name')
    @classmethod
    def check_unique_name(cls, v, info):
        db = get_db_session()
        exclude_id = info.data.get('id')
        query = db.query(Position).filter(
            Position.name == v,
            Position.is_delete == 0
        )
        if exclude_id:
            query = query.filter(Position.id != exclude_id)
        if query.first():
            raise ValueError('岗位名称已存在')
        return v

登录表单示例

python
# src/modules/auth/schemas.py
# +======================================================================
# | 模块: 登录表单验证
# | 说明: 用户登录的请求数据校验
# +======================================================================

from pydantic import BaseModel, Field

from core.config import CAPTCHA_LENGTH


# ============================================================
# 登录表单类
# ============================================================
class LoginForm(BaseModel):
    """登录表单验证类"""
    username: str = Field(..., min_length=1, max_length=20, description="登录账号")
    password: str = Field(..., min_length=6, max_length=128, description="登录密码")
    code: str = Field(..., min_length=CAPTCHA_LENGTH, max_length=CAPTCHA_LENGTH, description="验证码")
    key: str = Field(..., min_length=1, description="KEY值")

错误响应格式

验证失败时,全局异常处理器捕获 RequestValidationError 并返回标准格式:

json
{
    "code": 1,
    "data": null,
    "msg": "name: 字段长度不能少于1个字符/status: 输入值必须大于等于1",
    "ok": false
}

多个错误用 / 分隔。

总结

参数验证模块具备以下特点:

1. Pydantic v2:类型安全、自动解析 JSON 请求体
2. 丰富约束:min_length、max_length、ge、le、gt、lt、pattern
3. 自定义验证:@field_validator 实现复杂校验逻辑
4. BaseForm 基类:统一 id 字段处理,兼容前端空字符串
5. 唯一性校验:验证器中查询数据库,确保字段唯一性
6. 标准错误:全局异常处理器统一错误响应格式

小蚂蚁云团队 · 提供技术支持