Basic Usage

This library is meant to be called directly from higher level functions. Form processing usually involves two stages. The first stage prompts the user with a form to fill in. This stage requires generating defaults and instructions on how to fill the form. The second stage processes the form that the user submits after filling it in. Not all applications that need validation will require the first stage. For example APIs don’t usually send defaults to the developer before the developer makes a call to the API. We will discuss validation from a web form perspective in most examples unless otherwise noted.

Defining a form handler

The developer must at least define a schema. Here is a simple example of a handler:

email_form_handler = FormHandler(
        schema=BaseSchema(email=Email(not_empty=True)))

Prompting For Input

The developer should generate defaults and then pass those to the form handler in order to get back the form dict. This allows the handler to add more defaults, add filling arguments, encode defaults, setup the state and return a standardized dictionary to be used during form construction. Here is a simple example that populates a user’s email for them to change:

def _render_change_email(form_dict):
    return {'email_form': form_dict}

def prompt_change_email(request):
    defaults = {
        'email': request.user.email
    }
    form_dict = email_form_handler.prompt(defaults=defaults)
    return _render_change_email(form_dict)

Note that if not defaults are given the defaults will just be initialized to an empty UnicodeMultiDict.

Processing The Form

The developer should give the unsafe form params sent by the user to the handler. Then the developer should check for success or not and act accordingly. Here is a simple example that updates the user’s email.

def process_change_email(request):
    form_dict = email_form_handler.process(request.POST)
    if email_form_handler.was_success(form_dict):
        request.user.email = form_dict['defaults']['email']
        # redirect to something now.
    else:
        return _render_change_email(form_dict)

Using State

The state object provides a way for the developer to pass data to validators and hooks during form processing. Also the state object allows validators to pass additional information out to the caller of the handler after validation. For example a login validator might attach the actual user object to the state so that it can be retrieved by the caller.

All keyword arguments passed to prompt except for defaults will be set on the state object. All keyword arguments passed to process will be set on the state object. Calls to prompt and process where state is passed to validator might look like the following:

def prompt_change_username(request):
    # Pass the logged in user to the form handler.
    form_dict = form_handler.prompt(user=request.user)
    #...

def process_change_username(request):
    # Pass the logged in user to the form handler.
    form_dict = form_handler.process(request.POST, user=request.user)
    # ...

A call where state is retrieved from a validator might look like this:

def process_login(request):
    form_dict = form_handler.process(request.POST)
    if form_hander.was_success(form_dict):
        # User was set by a validator during processing.
        user = form_dict['state'].user
        # "Log in" the user.
        request.session['user_id'] = user.id
        request.session.save()
        # Redirect to something.
    else:
        # Re-render the login form.
        render_login_form(form_dict)

Contents of the form_dict

The form_dict object is just a plain python dictionary with the following keys: defaults, errors, state and fill_kwargs. The value of errors should evaluate to False when no errors have occurred. These have been mostly discussed before except for fill_kwargs.

The entry fill_kwargs is meant to be passed to something like formencode’s htmlfill() function. It contains the defaults and errors but also might contain keyword arguments that tell htmlfill more information such as the encoding to use. This can be useful so you don’t have to inject these all over your project.

Handler Hooks

Various hooks can be used to add more functionality to the handler. These hooks can be added by injecting them in __init__ during subclassing or by passing them in directly when creating a FormHandler instance. The hooks are described in the Hooks section.

Table Of Contents

Previous topic

Introduction

Next topic

Hooks

This Page