关于WTForms验证表单使用DataRequired的问题

声明

这篇文章所述内容可能会有一些问题,但是我目前没有发现问题,希望大家不吝赐教。

入正题吧

我在使用Flask框架进行web后台应用开发的过程当中,使用WTForms进行表单验证,在验证表单或者json数据的时候,使用DataRequired验证器验证数值类型字段会遇到一个问题,并且DataRequired的源码或者官方文档中也有这么一段提示

**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 the Optional validator and furthermore caused
confusion with certain fields which coerced data to 'falsey' values like
0, (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 the  attribute 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 the Optional validator and furthermore caused
    confusion with certain fields which coerced data to 'falsey' values like
    0, (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既可以做序列化和反序列化,也可以做数据校验。

1,621 次浏览

发表评论

电子邮件地址不会被公开。 必填项已用*标注