Chris Arndt added the following as ticket #2366 in our old Trac in 2010:
Find better solution for validation of arguments to controller methods set as error_handler
The current limit of one validation pass per request is not ideal in some situations. For example, for CRUD controllers, I constantly have to use the following pattern:
# This checks if the value is a valid foo ID and converts it into a matching Foo object # This keeps the controller methods free from boiler-plate database access code. foo_validator = ValidFoo() class FooCRUDController(controller.Controller) @expose(template="mypkg.templates.foo_new") @validate(validators=dict(foo=foo_validator)) def new(self, tg_errors=None, **kw): # When this method is run as the error handler of the 'create' method # the validate decorator of this method will not be effective # we therefore need to turn the foo ID into a Foo object manually. group = kw.get('foo') if not isinstance(foo, Foo): try: group = ValidFoo()._to_python(group, state=None) except validators.Invalid, exc: if tg_errors is None: tg_errors = dict() tg_errors['foo'] = exc values = dict() if not tg_errors and isinstance(group, Group): # display foo_create_form @expose() @validate(form=foo_create_form) @error_handler(new) def create(self, foo, attr1, attr2, ...): # create Foo object
The same pattern is used for the edit/update methods. Not only is this very tedious, error_prone and redundant (though I could probably write a custom validator for it), it is also only a workaround for a symptom and doesn't address the real problem, i.e. that validate decorater on the "new" method is ineffective, when "new" is run as the error handler of the "create" method.
Without knowing the internals of the validation framework, someone would probably just write:
class FooCRUDController(controller.Controller) @expose(template="mypkg.templates.foo_new") @validate(validators=dict(foo=ValidFoo())) def new(self, foo, tg_errors=None, **kw): if not tg_errors: # display foo_create_form @expose() @validate(form=foo_create_form) @error_handler(new) def create(self, foo, attr1, attr2, ...): # create Foo object
... and things would work as long there is no validation error. It has bitten me a hundred times when I forgot to use the above pattern and suddenly got strange results, because my "new" method received a string argument instead of an model object because the !ValidFoo validator was ineffective.
I have opened this ticket as a reminder to think about a better and more general solution for the whole validation / error_handler issue.