对请求数据的校验,选择使用 WTForms 进行校验,原生 WTForms 是对表单数据进行校验,而 API 请求是需要对请求体的参数进行校验,所以我们需要对他进行覆写。
原生的 Form 输出异常信息会以列表的形式,因为异常可能会有多个,在此我们将其拼接成一句 msg,这样会更便于前端展示。返回校验后的数据可以返回 dict 和 namedtuple 类型,也可以通过 get_data() 获取某一个参数。
# patch/validator.py
class Form(_Form):
def __init__(self):
data = request.get_json(silent=True)
args = request.args.to_dict()
super(Form, self).__init__(data=data, **args)
def validate_for_api(self):
"""
处理异常 拼接异常信息
"""
valid = super(Form, self).validate()
if not valid:
msg = ''
for index, item in enumerate(self.errors.values()):
msg += ';'.join(item)
if index != len(self.errors.values()) - 1:
msg += ';'
raise ParameterError(msg=msg)
return self
def get_data(self, *args):
data_list = []
for arg in args:
data_list.append(getattr(self._data, arg, None))
return data_list[0] if len(data_list) == 1 else tuple(data_list)
@property
def _data(self):
self.validate_for_api()
key_list, value_list = [], []
for key, value in self._fields.items():
if value.data is not None:
key_list.append(key)
value_list.append(value.data)
NamedTuple = namedtuple('NamedTuple', [key for key in key_list])
return NamedTuple(*value_list)
@property
def dt_data(self):
"""
返回dict类型
"""
return self._data._asdict()
@property
def nt_data(self):
"""
返回namedtuple类型
"""
return self._data
在查看了 WTForms 的文档后,我发现他的 IntegerField 在 DataRequired 尽然不支持数字0的,我不得不对它进行覆写,因为在我的理解里 0 也是 IntegerField。
class DataRequired(_DataRequired):
def __call__(self, form, field):
if field.type == 'IntegerField' and field.data == 0:
return
if not field.data or isinstance(field.data, string_types) and not field.data.strip():
if self.message is None:
message = field.gettext('This field is required.')
else:
message = self.message
field.errors[:] = []
raise StopValidation(message)
使用校验时尽量参考官方文档给出的类型和属性。
class UpdateUserValidator(Form):
nickname = StringField('昵称')
avatar = StringField('头像')
gender = SelectField('性别', choices=GenderEnum.choices(), validators=[Optional()])
age = IntegerField('年龄', validators=[Optional(), NumberRange(min=1, max=500, message='年龄超出范围')])
mobile = StringField('手机', validators=[
Optional(),
length(min=11, max=11, message='手机号长度为11位'),
Regexp(r'^1[3-9]\d{9}$', message='手机号不合法'),
])
WTForms 所支持的字段
字段类型 | 说明 |
---|---|
StringField | 文本字段 |
TextAreaField | 多行文本字段 |
PasswordField | 密码文本字段 |
HiddenField | 隐藏文本字段 |
DateField | 文本字段, 值为datetime.date格式 |
DateTimeField | 文本字段, 值为datetime.datetime格式 |
IntegerField | 文本字段, 值为整数 |
DecimalField | 文本字段, 值为decimal.Decimal |
FloatField | 文本字段, 值为浮点数 |
BooleanField | 复选框, 值为True 和 False |
RadioField | 一组单选框 |
SelectField | 下拉列表 |
SelectMultipleField | 下拉列表, 可选择多个值 |
FileField | 文件上传字段 |
SubmitField | 表单提交按钮 |
FormFiled | 把表单作为字段嵌入另一个表单 |
FieldList | 子组指定类型的字段 |
WTForms支持的表单的验证函数
验证函数 | 说明 |
---|---|
验证是电子邮件地址 | |
EqualTo | 比较两个字段的值; 常用于要求输入两次密钥进行确认的情况 |
IPAddress | 验证IP网络地址 |
Length | 验证输入字符串的长度 |
NumberRange | 验证输入的值在数字范围内 |
Optional | 无输入值时跳过其它验证函数 |
DataRequired | 确保字段中有数据 |
Regexp | 使用正则表达式验证输入值 |
URL | 验证url |
AnyOf | 确保输入值在可选值列表中 |
NoneOf | 确保输入值不在可选列表中 |