记录在 Flask 项目中使用 WTForms 自定义表单校验器的方法与注意事项。


一、使用场景

  • 默认的 WTForms 校验器不足以满足业务需求
  • 需要跨字段校验(如密码与确认密码一致)
  • 需要访问数据库进行校验(如用户名是否已存在)

二、自定义单字段校验器

WTForms 允许在表单类中定义 validate_<字段名> 方法进行校验。

from wtforms import Form, StringField, ValidationError

class MyForm(Form):
    username = StringField('用户名')

    def validate_username(self, field):
        if 'admin' in field.data.lower():
            raise ValidationError('用户名不能包含 admin')

三、通用函数式校验器

自定义函数式校验器可复用在多个表单字段中。

from wtforms import ValidationError

def no_special_chars(form, field):
    import re
    if re.search(r'[^a-zA-Z0-9]', field.data):
        raise ValidationError('不能包含特殊字符')

使用:

username = StringField('用户名', validators=[no_special_chars])

四、跨字段校验

需要同时访问多个字段时,可在表单类中重写 validate 方法。

class RegisterForm(Form):
    password = StringField('密码')
    confirm_password = StringField('确认密码')

    def validate(self):
        rv = super().validate()
        if not rv:
            return False
        if self.password.data != self.confirm_password.data:
            self.confirm_password.errors.append('两次密码不一致')
            return False
        return True

五、结合数据库校验

from models import User

def unique_username(form, field):
    if User.query.filter_by(username=field.data).first():
        raise ValidationError('用户名已存在')

六、小结

  • validate_<字段名> 适合字段独立校验
  • 函数式校验器便于复用
  • 跨字段校验需在 validate 方法中处理
  • 涉及数据库时要考虑性能与并发情况