Flask-WTForms RadioField自定义验证器消息不起作用

Rat*_*Don 6 python flask flask-wtforms

在中Flask-WTForms,我们可以为每个字段的每个验证器提供自定义消息。但是因为RadioField它仅显示默认消息。下面是一个例子。

>>> from wtforms import Form, RadioField, TextField
>>> from wtforms.validators import *
Run Code Online (Sandbox Code Playgroud)

文本域

>>> class MyForm(Form):
        x = TextField(u'Some text', validators = [Required(message="Hello")])
Run Code Online (Sandbox Code Playgroud)

错误信息

>>> form = MyForm()
>>> form.x.data
>>> form.validate()
False
>>> form.errors
{'x': ['Hello']}
Run Code Online (Sandbox Code Playgroud)

因此,TextField它显示了自定义错误消息。

无线电场

>>> class MyForm(Form):
        x = RadioField(choices = [(1, '1'), (2, '2')], validators = [Required(message="Hello")])
Run Code Online (Sandbox Code Playgroud)

错误信息

>>> form = MyForm()
>>> form.x.data
u'None'
>>> form.validate()
False
>>> form.errors
{'x': [u'Not a valid choice']}
Run Code Online (Sandbox Code Playgroud)

自定义错误消息不存在。我想,对于验证TextFieldRadioField将是不同的过程,可能这就是为什么它显示默认的消息。

所以我的问题是如何显示自定义消息以验证RadioField

vis*_*ell 5

你说得对,这个过程是不同的。

因此,如果您执行源代码,则有Field带有validate方法的基类。据说

"""
Validates the field and returns True or False. `self.errors` will
contain any errors raised during validation. This is usually only
called by `Form.validate`.

Subfields shouldn't override this, but rather override either
`pre_validate`, `post_validate` or both, depending on needs.> 

:param form: The form the field belongs to.
:param extra_validators: A sequence of extra validators to run.
"""
Run Code Online (Sandbox Code Playgroud)

验证的过程是pre_validate()-> validate()-> post_validate()(Call pre_validate-> Run validators -> Call post_validate)

你可以猜到,RadioField有它自己的pre_validate()方法,但基本上SelectField是一个。然后什么时候RadioField继承SelectField它也有它。

def pre_validate(self, form):
    for v, _ in self.choices:
        if self.data == v:
            break
    else:
        raise ValueError(self.gettext('Not a valid choice'))
Run Code Online (Sandbox Code Playgroud)

所以这就是为什么你'Not a valid choice'wtforms.validators.Required()验证器上得到错误而不是你的自定义错误,因为它只是没有通过pre_validate()它就停止了。

注意Required验证器已弃用,将在 WTForms 3.0 中删除,并且在拉取请求中,他们已经删除了它的用法。而不是Required()验证器,使用DataRequired()

更新:由于您将验证器添加到字段中,您仍然应该能够得到您的错误。因为因为pre_validate()只加注ValueError它不会停止validate()

# Call pre_validate
try:
    self.pre_validate(form)
except StopValidation as e:
    if e.args and e.args[0]:
        self.errors.append(e.args[0])
    stop_validation = True
except ValueError as e:
    self.errors.append(e.args[0])
Run Code Online (Sandbox Code Playgroud)

然后它去

# Run validators
if not stop_validation:
    chain = itertools.chain(self.validators, extra_validators)
    stop_validation = self._run_validation_chain(form, chain)
Run Code Online (Sandbox Code Playgroud)

这是您的验证器存在并且应该将新错误添加到错误列表(form.x.error)中,但是它转换None'None',因此您form.x.data变为'None'str类型),现在它变为__call__

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)
Run Code Online (Sandbox Code Playgroud)

条件not field.dataFalse,因为field.data'None'。为什么数据从None'None'forSelectField及其相关数据在 GitHub 上的问题中进行了解释,并且可能会在Pull Request合并到 master 中时得到修复。