close Warning: Can't synchronize with repository "(default)" (Unsupported version control system "svn": No module named svn). Look in the Trac log for more information.

Version 7 (modified by cmlenz, 16 years ago) (diff)

--

Form Processing

Diva comes with a simple module supporting the processing of HTML forms. A request handler that does some simple form processing typically looks something like this:

from diva.forms import Form, TextValidator
from diva.routing import redirect_to
from diva.templating import output, render

class LinkForm(Form):
    username = TextValidator(required=True)
    url = TextValidator(required=True, pattern=r'^https?://')
    title = TextValidator(required=True)

@output('submit.html')
def submit(request, response):
    form = LinkForm()
    if request.method == 'POST':
        if 'cancel' in request.POST:
            redirect_to('home')
        if form.validate(request.POST):
            # Form is valid, store data into the database
            link = Link(**form.data)
            link.store(app.db)
            redirect_to('info', link.id)
    return render(errors=form.errors)

This simple example already does a couple of things you may not expect:

  • When the form is redisplayed on POST due to validation errors, the form elements will already be populated with the previously entered values.
  • The form submission is protected against Cross-Site Request Forgery (CSRF) attacks, by adding a form token both as a cookie, and as a hidden form input field.

HTML Forms in Templates

Diva does not generate HTML markup for your forms automatically. The diva.forms package is only concerned with the form data, not the rendering of individual form elements and how they are assembled into the larger form.

For the form defined above, a simple template might contain something like this:

<form action="" method="post">
  <p>
    <label>Your name: <input type="text" name="username" /></label>
    <span py:if="'username' in errors" class="error">${errors.username}</span>
  </p><p>
    <label>Link URL: <input type="text" name="url" /></label>
    <span py:if="'url' in errors" class="error">${errors.url}</span>
  </p><p>
    <label>Title: <input type="text" name="title" /></label>
    <span py:if="'title' in errors" class="error">${errors.title}</span>
  </p>
  <hr />
  <p>
    <input type="submit" />
  </p>
</form>

Note that while you don't need to manually take care of filling in the form values, you do have to explicitly add any error messages that need to be displayed after a failed validation.

Of course, you can use Genshi macros to reduce the repetitive nature of defining forms this way. But because the form layout used on one site is probably different than the layout used by other sites, you need to define such macros yourself. But it's pretty simple, really.

API Documentation

Error: Macro PythonDoc(trunk, diva.forms) failed
Unsupported version control system "svn": No module named svn