In Flask-WTForms
, we can give a custom message for each validator for each field. But for RadioField
it shows the default message only. Below is an example.
>>> from wtforms import Form, RadioField, TextField
>>> from wtforms.validators import *
TextField
>>> class MyForm(Form):
x = TextField(u'Some text', validators = [Required(message="Hello")])
Error Message
>>> form = MyForm()
>>> form.x.data
>>> form.validate()
False
>>> form.errors
{'x': ['Hello']}
So for a TextField
it shows the custom error message.
RadioField
>>> class MyForm(Form):
x = RadioField(choices = [(1, '1'), (2, '2')], validators = [Required(message="Hello")])
Error Message
>>> form = MyForm()
>>> form.x.data
u'None'
>>> form.validate()
False
>>> form.errors
{'x': [u'Not a valid choice']}
The custom error message is not there. I guess, validation for TextField
and RadioField
will be different process and may be that's why it's showing the default message.
So my Question is How to show a custom message for the validation of a RadioField
?
You are right about that the process is different.
So if you go do source code there is base Field
class with validate
method. It's said
""" 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. """
And the procedure of validation is pre_validate()
-> validate()
-> post_validate()
(Call pre_validate
-> Run validators -> Call post_validate
)
As you can guess, RadioField
has it's own pre_validate()
method, but basically SelectField
's one. And then when RadioField
is inherit from SelectField
it has it too.
def pre_validate(self, form): for v, _ in self.choices: if self.data == v: break else: raise ValueError(self.gettext('Not a valid choice'))
So that's why you get 'Not a valid choice'
error instead of your custom one, on wtforms.validators.Required()
validator, because it just didn't go through the pre_validate()
and it stops.
Note: Required
validator is depracated and will be removed in WTForms 3.0, and in that pull request they already removed it's usage. Instead of Required()
validator, use DataRequired()
UPDATE: Since you add your validator to field you still should be able to get your error. Because since pre_validate()
raises only ValueError
it doesn't stop 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])
And then it goes to
# Run validators if not stop_validation: chain = itertools.chain(self.validators, extra_validators) stop_validation = self._run_validation_chain(form, chain)
And here is your validator exists and should add new error to the list of errors(form.x.error
), however it converts None
to 'None'
, so your form.x.data
becomes 'None'
(str
type), and now it goes to __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)
And the condition not field.data
is False
, because field.data
is 'None'
.
Why data convert from None
to 'None'
for SelectField
and its related ones is explained in Issue on GitHub and probably be fixed when Pull Request will be merged in master.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With