Skip to content

参数验证

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

基本用法

定义表单类

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

from typing import Optional

from pydantic import BaseModel, Field
from core.base_schema import BaseSchema


# ============================================================
# 岗位表单类
# ============================================================
class PositionForm(BaseSchema):
    """岗位创建/编辑表单"""
    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-停用")

Handler 使用

python
class PositionAddHandler(BaseHandler):
    @permission_required("sys:position:add")
    @check_demo
    async def post(self):
        return await position_service.add(self)

自动验证

Service 层的 _validate() 方法自动完成参数验证。验证失败时返回标准格式错误:

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(BaseSchema):
    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

BaseSchema 基类

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

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

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

from typing import Optional

from pydantic import BaseModel, Field, field_validator


# ============================================================
# 表单基类
# ============================================================
class BaseSchema(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

前端空字符串

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

唯一性校验

唯一性校验通过 Service 层的 unique_fields 声明实现:

python
class PositionService(BaseService):
    model = Position
    repo_cls = PositionRepository
    unique_fields = {'name': '岗位名称不能重复'}

BaseService._check_unique()add()update() 时自动查询数据库判断是否重复,无需在 Schema 中手写校验逻辑。


## 登录表单示例

```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. BaseSchema 基类:统一 id 字段处理,兼容前端空字符串
5. 唯一性校验:验证器中查询数据库,确保字段唯一性
6. 标准错误:全局异常处理器统一错误响应格式

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