How do I validate wtforms fields against one another?
Solution 1
You can override validate
in your Form
...
class MyForm(Form):
select1 = SelectField('Select 1', ...)
select2 = SelectField('Select 2', ...)
select3 = SelectField('Select 3', ...)
def validate(self):
if not Form.validate(self):
return False
result = True
seen = set()
for field in [self.select1, self.select2, self.select3]:
if field.data in seen:
field.errors.append('Please select three distinct choices.')
result = False
else:
seen.add(field.data)
return result
Solution 2
You can use the form in your validation to get the value of other fields.
For example:
def validate_name(form, field):
if form.other_variable.data == 'checked' and len(field.data) > 10:
raise validation_error("say somgthing")
Solution 3
I wrote a small python library required to make cross-field validation like this easier. You can encode your validation logic declaratively as pairwise dependencies. So your form may look like:
from required import R, Requires, RequirementError
class MyForm(Form):
VALIDATION = (
Requires("select1", R("select1") != R("select2") +
Requires("select2", R("select2") != R("select3") +
Requires("select3", R("select3") != R("select1")
)
select1 = SelectField('Select 1', ...)
select2 = SelectField('Select 2', ...)
select3 = SelectField('Select 3', ...)
def validate(self):
data = {
"select1": self.select1.data,
"select2": self.select2.data,
"select3": self.select3.data,
}
# you can catch the RequirementError
# and append the error message to
# the form errors
self.VALIDATION.validate(data)
return result
You can take the VALIDATION object and append more validation rules or even put it in a separate module and import / reuse validation rules in different places.
Related videos on Youtube
Comments
-
YPCrumble almost 2 years
I have three identical
SelectField
inputs in a form, each with the same set of options. I can't use one multiple select.I want to make sure that the user selects three different choices for these three fields.
In custom validation, it appears that you can only reference one field at a time, not compare the value of this field to others. How can I do that? Thanks!
-
YPCrumble about 10 yearsThanks - why the line
if not Form.validate(self):
? That keeps firing when I try your suggestion and the validation doesn't run. -
FogleBird about 10 yearsThat's to do the default validation (as if you hadn't overridden validate)
-
FogleBird about 10 yearsThe other steps are to perform validation across multiple fields, as you asked.
-
Jimmy over 7 yearsI just want to add, that I was confused by overriding here. Referring to O'Reilly Learning Python, I would call this extending the validate method. As you're still invoking the default behavior when you call
if not Form.validate(self)
And then the custom validation code runs. When I read that, it cleared things up for me. Still @FogleBird great answer -
Dan Passaro over 7 yearsIf you're on Python 3, better to write
super().validate()
thanForm.validate(self)
. If you're on Python 2, usesuper(MyForm, self).validate()
.