Discussion:
[FE-discuss] Again chained validators
Andrea Riciputi
2009-05-05 13:07:25 UTC
Permalink
Hi all,
I'm still trying to wrap my head around chained validators, I hope you
can help me a little.

Suppose I have a form with several fields in it, and many of them are
somewhat coupled together. For example I have a field "foo" whose
value must be one out of a list **but** if another field "bar" has a
certain value then "foo" must have a specific value.

In a case like this I build up a schema like the following:

...
foo = OneOf(allowed_list)
bar = String()
chained_validator = [CheckFooBar()]

where CheckFooBar() is:

class CheckFooBar(FormValidator):
def validate_python(self, values, state):
# validation code here

So far so good. The problem arise when I have several fields in a form
with many different chained validators like CheckFooBar() attached to
the schema. If one of them fails the following ones are not run and it
could take many re-submission to the user to discover all the
mistakes. That's not user friendly at all.

As a possible solution I could define my chained validator like this:

class CheckFooBar(FormValidator):
validate_partial_form = True
def validate_partial(self, values, state):
# validation code here

In this case all the chained validators are run no matter if they fail
or not, however these chained validator are also run even if one of
the primitive validators (those declared in the schema) fails.

As a consequence of this, the values passed to validate_partial() are
the original values coming from the user input, leaving to
validate_partial() the task of checking if the those values are there
and if they are of the right type (i.e. I must recode the validation
process inside validation_partial()!).

Since all this stuff doesn't make too much sense to me, I guess there
should be a different approach to this kind of problem. Unfortunately
I can't see it. What's the right approach to check "coupled" fields?
Is there any way to get multiple chained validators to fails without
re-invent the validation-wheel?

Suggestions and comments are always welcome.

Cheers,
Andrea
Ian Bicking
2009-05-05 17:39:07 UTC
Permalink
Post by Andrea Riciputi
Hi all,
I'm still trying to wrap my head around chained validators, I hope you
can help me a little.
Suppose I have a form with several fields in it, and many of them are
somewhat coupled together. For example I have a field "foo" whose
value must be one out of a list **but** if another field "bar" has a
certain value then "foo" must have a specific value.
...
foo = OneOf(allowed_list)
bar = String()
chained_validator = [CheckFooBar()]
# validation code here
So far so good. The problem arise when I have several fields in a form
with many different chained validators like CheckFooBar() attached to
the schema. If one of them fails the following ones are not run and it
could take many re-submission to the user to discover all the
mistakes. That's not user friendly at all.
validate_partial_form = True
# validation code here
In this case all the chained validators are run no matter if they fail
or not, however these chained validator are also run even if one of
the primitive validators (those declared in the schema) fails.
As a consequence of this, the values passed to validate_partial() are
the original values coming from the user input, leaving to
validate_partial() the task of checking if the those values are there
and if they are of the right type (i.e. I must recode the validation
process inside validation_partial()!).
Yes, this is why validate_partial isn't done by default, it requires a more
careful validation of the fields.
Post by Andrea Riciputi
Since all this stuff doesn't make too much sense to me, I guess there
should be a different approach to this kind of problem. Unfortunately
I can't see it. What's the right approach to check "coupled" fields?
Is there any way to get multiple chained validators to fails without
re-invent the validation-wheel?
Well, it seems like you might simply need a bit more granularity. I.e., you
have a validator that *must* pass before you care about any of the other
validators. You could then do:

class EssentialSchema(Schema):
... stuff ...
chained_validators = Schema(chained_validators=[all these secondary
validators])

Because the Schema instance itself won't validate partially validated forms,
all of EssentialSchema must pass before more validation is done.

Another is simply to factor your chained validators carefully so that you
check easy stuff in validate_partial, but maybe leave some more complex
stuff for full validation.
--
Ian Bicking | http://blog.ianbicking.org
Loading...