6.5 KiB
6.5 KiB
WTForms Schema规范
概述
项目使用 WTForms 进行请求数据校验。所有请求体参数通过 WTForms 表单类定义,框架在调用 Router 前自动完成解析和验证。
:::tip 核心原则
- 请求体参数必须声明为 WTForms 表单类(Form 类)
- 字段约束使用
validators定义 - 自定义校验使用
validate_方法 - 唯一性校验在 Schema 中查询数据库 :::
命名规范
| 类型 | 命名格式 | 示例 |
|---|---|---|
| 创建/编辑表单 | {模块}Form |
PositionForm |
| 状态更新表单 | {模块}StatusForm |
PositionStatusForm |
| 查询参数表单 | {模块}QueryForm |
PositionQueryForm |
:::tip 继承 BaseForm
创建/编辑表单继承 src.common.forms.base_form.BaseForm,自动获得 id 字段(编辑时必填)。
:::
PositionForm 示例
以岗位模块为例,src/modules/system/position/schema.py 完整内容:
from wtforms import StringField, IntegerField
from wtforms.validators import DataRequired, Length, NumberRange
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')
])
:::tip BaseForm 基类
BaseForm(定义在 src/common/forms/base_form.py)提供 id 字段和数据清洗功能,自动将前端传入的空字符串 ''/'null'/'undefined' 转为 None,避免 WTForms 解析报错。
:::
Validator 约束
| Validator | 类型 | 说明 | 示例 |
|---|---|---|---|
DataRequired |
any | 必填字段 | DataRequired(message='不能为空') |
Length |
str | 字符串长度 | Length(min=1, max=150) |
NumberRange |
int/float | 数值范围 | NumberRange(min=0, max=99999) |
Optional |
any | 可选字段 | Optional() |
Email |
str | 邮箱格式 | Email(message='邮箱格式不正确') |
URL |
str | URL 格式 | URL(message='URL格式不正确') |
Regexp |
str | 正则表达式 | Regexp(r'^[a-zA-Z]+$') |
:::tip Validator 说明
DataRequired:必填字段,不允许空值Length:字符串长度限制NumberRange:数值范围限制Optional:可选字段 :::
自定义校验器
唯一性校验
from wtforms import ValidationError
from src.modules.system.position.repository import PositionRepository
class PositionForm(BaseForm):
"""岗位创建/编辑表单"""
name = StringField('岗位名称', validators=[
DataRequired(message='岗位名称不能为空'),
Length(min=1, max=150, message='岗位名称长度必须在1-150个字符之间')
])
def validate_name(self, field):
"""岗位名称唯一性校验"""
exclude_id = self.id.data if self.id.data else None
if PositionRepository.exists_by([Position.name == field.data], exclude_id):
raise ValidationError('岗位名称不能重复')
格式校验
from wtforms import ValidationError
import re
class UserForm(BaseForm):
"""用户创建/编辑表单"""
username = StringField('用户名', validators=[
DataRequired(message='用户名不能为空'),
Length(min=3, max=50, message='用户名长度必须在3-50个字符之间')
])
email = StringField('邮箱', validators=[
DataRequired(message='邮箱不能为空'),
Length(max=100, message='邮箱长度不能超过100个字符')
])
phone = StringField('手机号', validators=[
Optional(),
Length(max=20, message='手机号长度不能超过20个字符')
])
def validate_username(self, field):
"""用户名只允许字母、数字、下划线"""
if not re.match(r'^[a-zA-Z0-9_]+$', field.data):
raise ValidationError('用户名只允许字母、数字、下划线')
def validate_email(self, field):
"""邮箱格式校验"""
if not re.match(r'^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$', field.data):
raise ValidationError('邮箱格式不正确')
def validate_phone(self, field):
"""手机号格式校验(可选字段,有值时校验)"""
if field.data and field.data != '':
if not re.match(r'^1[3-9]\d{9}$', field.data):
raise ValidationError('手机号格式不正确')
:::tip validator 规则
- 方法名必须为
validate_{field_name} - 校验失败抛出
ValidationError(错误消息) - 可选字段需判断
None值 :::
在 Router 中使用
@position_blue.route('/add', methods=['POST'])
@check_permission('sys:position:add')
def add():
"""
新增岗位
"""
from src.modules.system.position.service import add_position
from src.modules.system.position.schema import PositionForm
data = parse_request_body(request, PositionForm)
return add_position(data)
:::tip 数据访问
Service 层通过 data['field'] 直接访问字段。WTForms 在进入 Router 之前已完成校验,Service 无需重复验证。
:::
错误响应
WTForms 校验失败时,由框架自动转换:
{
"code": 1,
"data": null,
"msg": "岗位名称不能为空",
"ok": false
}
总结
WTForms Schema 规范要求:表单类命名 {Module}Form,继承 BaseForm;字段约束用 validators 定义长度/范围;自定义校验用 validate_{field_name} 方法抛 ValidationError;唯一性校验通过 Repository.exists_by(filters, exclude_id) 实现。框架自动解析和验证,Service 通过 form.data['field'] 访问已校验的数据。