views:

72

answers:

2

Hi everyone!

I'm building a web frontend to a server-side application, using Pylons 1.0.
Right now I'm writing the first form, and I'm facing a problem concerning validation.. Using FormEncode and the @validate decorator I can easily validate the user input from a client-side perspective, but when I submit the data to the server, it may perform additional checks and eventually throw back exceptions that I need to show to the user.

My question: is there a concise way to integrate/emulate this exception handling into the FormEncode/validate flow? For example, redisplay the form with filled fields and an error message, as would happen if the exception had come from the @validate itself?

Here's what I have at the moment:

def edit(self, id):
    return render('/edit_user.mako')

@validate(schema=form.UserForm(), form="edit")
def add_user(self):
    if request.POST:
        u = helpers.load_attributes(User(), self.form_result)
        try:
            model.save_to_server(u)
        except MyBaseException, exc:
            helpers.flash(unicode(exc))
            return self.edit()

In this way, in case of a server-side exception I can see the "flash" message but the form of course will have empty fields :/

+1  A: 

I like to implement:

from formencode import htmlfill

def create(self):
    if request.params:
        try:
            Post.validate(request.paramse)
            post = helpers.load_attributes(Post(), request.params)
            model.save_to_server(post)

            flash('OK', 'success')
            redirect(...)
        except InvalidException as e:
            for key, message in e.unpack_errors().iteritems():
                flash(message, 'error')

    return htmlfill.render(render('/blogs/create.html'), request.params)

where my Post.validate:

@staticmethod
def validate(data):
    schema = PostSchema()
    schema.to_python(data)

In this way, if is the first time (request.params empty) html fills form with nothing, when user send datas html fills form with request.params

renatopp
A: 

Another way (inspired by this answer) is to write a decorator similar to @validate that would catch the desired exceptions and use htmlfill to display their message:

def handle_exceptions(form):

    def wrapper(func, self, *args, **kwargs):
        try:
            return func(self, *args, **kwargs)
        except MyBaseException, e:
            request = self._py_object.request
            errors = { "exception" : unicode(e) }

            params = request.POST
            decoded = params.mixed()
            request.environ['REQUEST_METHOD'] = 'GET'
            self._py_object.tmpl_context.form_errors = errors
            request.environ['pylons.routes_dict']['action'] = form
            response = self._dispatch_call()

            # If the form_content is an exception response, return it
            if hasattr(response, '_exception'):
                return response

            htmlfill_kwargs2 = {}
            htmlfill_kwargs2.setdefault('encoding', request.charset)
            return htmlfill.render(response, defaults=params, errors=errors,
                                   **htmlfill_kwargs2)
    return decorator(wrapper)

The decorator would be used like:

@handle_exceptions("edit")
@validate(schema=form.UserForm(), form="edit")
def add_user(self):
    if request.POST:
        u = helpers.load_attributes(User(), self.form_result)
        model.save_to_server(u)
Joril