声明
这篇文章所述内容可能会有一些问题,但是我目前没有发现问题,希望大家不吝赐教。
入正题吧
我在使用Flask框架进行web后台应用开发的过程当中,使用WTForms进行表单验证,在验证表单或者json数据的时候,使用DataRequired验证器验证数值类型字段会遇到一个问题,并且DataRequired的源码或者官方文档中也有这么一段提示
**NOTE** this validator used to be calledRequired
but the way it behaved (requiring coerced data, not input data) meant it functioned in a way which was not symmetric to theOptional
validator and furthermore caused confusion with certain fields which coerced data to 'falsey' values like0
,
(0)
,
(0)
etc. Unless a very specific reason exists, we recommend using the :class:
InputRequired
instead.
这里我只阐述验证整型字段,当你要验证的表单里面有IntegerField的时候,并且这个字段允许值为0的情况下,使用DataRequired作为验证器:你可以使用postman进行接口请求测试,当你的请求数据类型是application/x-www-form-urlencoded的时候,将该字段值填成0,没有问题,后台验证能够通过,但是当你将application/json的时候,你将该字段的值填写为0,后台验证器DataRequired就验证通不过,因为在以表单类型发送的时候,postman会将整型字段当做字符串处理, 如果是以json类型发送的话,会保持整型发送到后台,然后结合DataRequired源码可以看出
class DataRequired(object): """ Checks the field's data is 'truthy' otherwise stops the validation chain. This validator checks that theattribute on the field is a 'true' value (effectively, it does
field.data
.) Furthermore, if the data is a string type, a string containing only whitespace characters is considered false. If the data is empty, also removes prior errors (such as processing errors) from the field. **NOTE** this validator used to be called
Required
but the way it behaved (requiring coerced data, not input data) meant it functioned in a way which was not symmetric to theOptional
validator and furthermore caused confusion with certain fields which coerced data to 'falsey' values like0
,
(0)
,
(0)
etc. Unless a very specific reason exists, we recommend using the :class:
InputRequired
instead. :param message: Error message to raise in case of a validation error. """ field_flags = ('required', ) def __init__(self, message=None): self.message = message def __call__(self, form, field): 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)
在__call__函数中,if not field.data这句便知,数值0是通不过验证的,但是字符串”0″是可以通过的,我查找资料看到网上有人说InputRequired可以,我试了,结果当时搞出一堆奇怪的现象,这里就不详细阐述错误的现象了,不信,你们可以自己去试。注意这里我使用Flask是开发前后台分离项目,Flask只开发API后台,提供给web前端(基于Vue框架)、PC客户端(Qt开发)、安卓APP调用,这里没有使用Flask的模板那一套。
解决问题
为了解决验证IntegerField的问题,于是我就看DataRequired的源码有没有问题,想着自己实现一个DataRequired类来代替官方的DataRequired,便继承了DataRequired类实现一个IntegerDataRequired,代码如下
class IntegerDataRequired(DataRequired): """主要是为了解决DataRequired在验证IntegerField时候,无法校验通过falsey的数据,比如0等""" field_flags = ('required',) def __init__(self, message=None): self.message = message def __call__(self, form, field): if field.data is None 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)
其实就改了一句话,把__call__中的if field.data 改成了if field.data is None,这样可以适用于验证IntegerField类型的字段了,其实应该也适用于验证所有类型的字段的Required了(如果真是这么简单,为什么官方不直接修改了呢),但是其实我对自己的Python水平或者对于Flask的了解并没有那么自信,所以暂时将该类的名字叫做IntegerDataRequired,只用来验证IntegerField字段,其他的还是使用官方的DataRequired验证器,后续使用过程当中如果发现什么问题也好修改,不过目前来看,IntegerDataRequired能够满足我验证IntegerField的需求了。
如果各位对于上述的IntegerDataRequired类觉得有什么问题的话,欢迎指正,互相学习,谢谢。
PS:目前觉得WTForms用来验证纯API后台请求的数据(表单或者json)并不是那么美好,并且WTForms的活跃度也不是很高,后续使用可能将尝试marshmallow既可以做序列化和反序列化,也可以做数据校验。