Latest Version: 0.9.6.2
  Dashboard > Pylons Cookbook > ... > Forms > Validation done manually
  Pylons Cookbook Log In | Sign Up   View a printable version of the current page.  
  Validation done manually
Added by Christoph Haas, last edited by Christoph Haas on Jul 18, 2008  (view change)
Labels: 
(None)

Validation done manually (aka "die, @validate, die")

For my taste the @validate decorator is not flexible enough. So I found myself doing the form validation with FormEncode a little more verbose and manually.

This is the validate function that does the actual validation:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
def validate(schema, **state_kwargs):
    """Validate a formencode schema.
    Works similar to the @validate decorator. On success return a dictionary
    of parameters from request.params. On failure throws a formencode.Invalid
    exception."""
    # Create a state object if requested
    if state_kwargs:
        state = State(**state_kwargs)
    else:
        state = None

    # In case of validation errors an exception is thrown. This needs to
    # be caught elsewhere.
    return schema.to_python(pylons.request.params, state)

The state is nothing fancy. Just a simple Python object with some attributes.
A state can be passed to the validator to transport information like who is
currently logged in. The state is completely optional here. My state object is just:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
class State(object):
    """Trivial class to be used as State objects to transport information to formencode validators"""
    def __init__(self, **kw):
        for key in kw:
            setattr(self, key, kw[key])

    def __repr__(self):
        atts = []
        for key in self.__dict__:
            atts.append( (key, getattr(self, key)) )

        return self.__class__.__name__ + '(' + ', '.join(x[0] + '=' + repr(x[1]) for x in atts) + ')'

In case the validation failed you want to redisplay the current HTML page
and decorate the input fields with the appropriate error messages just like
the @validate decorator does. This is the function I use to prepare such
a page with error messages:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
def htmlfill(html, exception_error=None):
    """Add formencode error messages to an HTML string.
    'html' contains the HTML page with the form (e.g. created with render()).
    'exception_error' is the formencode.Invalid-Exception from formencode."""
    return formencode.htmlfill.render(
        form=html,
        defaults=pylons.request.params,
        errors=(exception_error and exception_error.unpack_errors()),
        encoding=pylons.response.determine_charset()
    )

Now this is how you would use these functions in your controller:

1
2
3
4
5
6
try:
    fields = validate(MyValidationSchema)
except formencode.Invalid, e:
    return htmlfill(self.index(), e)

# 'fields' now contains the form information.

I'm using this code in production and it does what I expect. Let me know if you have improvements or ideas.

Christoph

Site running on a free Atlassian Confluence Open Source Project License granted to Pylons. Evaluate Confluence today.
Powered by Atlassian Confluence, the Enterprise Wiki. (Version: 2.3.3 Build:#645 Feb 13, 2007) - Bug/feature request - Contact Administrators
Top