Files
djangoadmin-wiki/DjangoAdmin_Flask_NaiveVue/zh/volume2/schema.md
T
2026-09-12 23:12:15 +08:00

6.5 KiB
Raw Blame History

WTForms Schema

Schema 层负责请求数据的校验。项目使用 WTForms 定义表单类,通过 validators 约束字段格式,框架在接收请求体时自动执行校验。

文件位置

src/modules/system/position/schema.py

完整代码

from wtforms import StringField, IntegerField
from wtforms.validators import DataRequired, Length, NumberRange, Optional

from src.common.forms.base_form import BaseForm


# ============================================================
# 岗位表单类
# ============================================================
class PositionForm(BaseForm):
    """岗位创建/编辑表单"""
    name = StringField('岗位名称', validators=[
        DataRequired(message='岗位名称不能为空'),
        Length(min=1, max=150, message='岗位名称长度必须在1-150个字符之间')
    ])
    status = IntegerField('岗位状态', validators=[
        DataRequired(message='岗位状态不能为空'),
        NumberRange(min=1, max=2, message='岗位状态必须是1或2')
    ])
    sort = IntegerField('岗位排序', validators=[
        DataRequired(message='岗位排序不能为空'),
        NumberRange(min=0, max=99999, message='岗位排序必须在0-99999之间')
    ])


# ============================================================
# 设置状态表单类
# ============================================================
class PositionStatusForm(BaseForm):
    """岗位状态更新表单"""
    id = IntegerField('岗位ID', validators=[
        DataRequired(message='岗位ID不能为空'),
        NumberRange(min=1, message='岗位ID必须大于0')
    ])
    status = IntegerField('岗位状态', validators=[
        DataRequired(message='岗位状态不能为空'),
        NumberRange(min=1, max=2, message='岗位状态必须是1或2')
    ])

代码解析

基类选择

基类 用途 包含字段
BaseForm 创建/编辑通用表单 自带可选 id 字段(Optional),编辑时传入
特定操作表单 无额外字段,按需定义

创建和编辑共用 PositionForm:创建时不传 id,编辑时传入 id。BaseForm 的 id 字段定义为 IntegerField('ID', validators=[Optional()]),创建时可省略。

Validator 约束

name = StringField('岗位名称', validators=[
    DataRequired(message='岗位名称不能为空'),
    Length(min=1, max=150, message='岗位名称长度必须在1-150个字符之间')
])
Validator 含义
DataRequired 必填字段,不允许空值
Length(min=1, max=150) 字符串长度限制
NumberRange(min=1, max=2) 数值范围限制
Optional 可选字段
status = IntegerField('岗位状态', validators=[
    DataRequired(message='岗位状态不能为空'),
    NumberRange(min=1, max=2, message='岗位状态必须是1或2')
])
参数 含义
min=1 最小值(大于等于)
max=2 最大值(小于等于)
message 校验失败时的错误信息
sort = IntegerField('岗位排序', validators=[
    DataRequired(message='岗位排序不能为空'),
    NumberRange(min=0, max=99999, message='岗位排序必须在0-99999之间')
])

排序字段允许 0 到 99999 的范围。

状态更新单独建类

# ============================================================
# 设置状态表单类
# ============================================================
class PositionStatusForm(BaseForm):
    """岗位状态更新表单"""
    id = IntegerField('岗位ID', validators=[
        DataRequired(message='岗位ID不能为空'),
        NumberRange(min=1, message='岗位ID必须大于0')
    ])
    status = IntegerField('岗位状态', validators=[
        DataRequired(message='岗位状态不能为空'),
        NumberRange(min=1, max=2, message='岗位状态必须是1或2')
    ])

状态更新接口只需要 id 和 status 两个字段,与创建/编辑表单分开定义,接口语义更清晰。

如何在 Router 中使用

from flask import Blueprint, request
from src.common.utils.request import parse_request_body
from src.modules.system.position import service as position
from src.core import response as R

position_blue = Blueprint('position', __name__, url_prefix='/position')


@position_blue.route('/add', methods=['POST'])
def add():
    """新增岗位"""
    json_data, err = parse_request_body()
    if err:
        return R.failed(msg=err)
    position.add_position(json_data)
    return R.ok(msg="添加成功")

parse_request_body 函数自动解析请求体 JSON。校验失败时,Service 层抛出 BizError,由异常处理器自动返回标准错误响应:

{
  "code": 1,
  "data": null,
  "msg": "岗位名称不能为空"
}

自定义校验器

如果需要自定义校验逻辑,可以在表单类中定义 validate_ 开头的方法:

class PositionForm(BaseForm):
    """岗位创建/编辑表单"""
    name = StringField('岗位名称', validators=[
        DataRequired(message='岗位名称不能为空'),
        Length(max=150, message='岗位名称长度不得超过150个字符')
    ])

    def validate_name(self, field):
        """自定义校验:检查岗位名称是否已存在"""
        from src.modules.system.position.repository import PositionRepository
        if not field.data:
            return
        current_id = self.id.data if self.id.data else None
        if PositionRepository.exists_by({'name': field.data}, exclude_id=current_id):
            raise ValidationError('岗位名称已存在')

开发要点

  1. 创建/编辑共用一个表单类:继承 BaseForm,利用其内置的可选 id 字段
  2. 特殊操作单独建类:如状态更新、排序调整等,只包含必要的字段
  3. 合理设置 Validator:DataRequired / Length / NumberRange 等,让框架自动校验
  4. message 必填:用于返回给前端的错误信息,方便调试
  5. 唯一性校验:通过自定义 validate_ 方法实现,使用 Repository 层的 exists_by(filters, exclude_id) 方法

总结

WTForms Schema 通过 BaseForm 继承公共字段(id 等),使用 validators 声明约束,自定义 validate_ 方法实现唯一性校验。唯一性校验使用 Repository.exists_by({'field': value}, exclude_id=current_id) 方法,自动过滤软删除记录并支持排除自身。特殊操作单独建类,message 必填用于返回给前端的错误信息。