2009-05-07

Forms that don't make you tense and nervous

Forms are tedious. I used to think that some five thousand lines of code was the remedy [1]. All the pesky details are abstracted away and in their stead is a very reasonable model based on schemas, widgets, converters, add forms, edit forms, display forms, page forms, subforms–rest assured, there's an option that fits you.

Invariably, with any framework you'll need to adjust things a bit. As it happens, this is where it gets tedious with the framework that is supposed to remedy tediousness. Endless abstraction and delegation makes it difficult to plug in custom behavior, let alone come to terms with what needs to be plugged out and how to write the code to replace it.

Typesetting documents in Latex is similar; you'll spend hours trying to align four graphs on a page, because "letting the system do it for you" doesn't get you where you want. The better you're acquainted with the system, headaches will come fewer and farther between–the learning curve pays off. Yet, arguably not all documents are best typeset in Latex.

Where's the restructured text of forms? There's Ian Bicking's FormEncode. It does some of the things I want and it does a lot of things I don't want. It also does the things I do want in a way I don't quite like.

Sanctioned by the "scratch your own itch" approach to software development (if it works for you, chances are it'll work for others), Stefan Eletzhofer and I decided to write a minimalistic form library called repoze.formapi. Part of the library was actually written with Ian present, while Jeroen Vloothuis wrote most of the error handling and validation logic. The result is a very usable library which intentionally does very little. It provides powerful field marshalling, flexible validation and a minimalistic form class framework. You write your own HTML.

Note: Narrative documentation for the library is now available.

[1] z3c.form

5 comments:

Laurence Rowe said...

I'm not entirely convinced... it reminds me of writing forms back in the Plone 1 and 2.0 days - great flexibility when there are only a few, but unwieldy when you have many and you want to keep a consistent look and feel.

Wichert said...

That depends very much on the application. A lot of my recent projects have a high design element to them, so all forms are hand-made and styled (see this registration form for example). For that use case a tool such as repoze.formapi is ideal. I looked at z3c.form and it only gets in the way for this type of usage.

For use cases involving auto-generated forms you will need a bit more, but that can be done on top of a layer like formapi.

malthe said...

There's definitely a point where it gets unwieldy, but many apps never get to it. Arguably things can also get quite unwieldy when using the schema-based form frameworks, simply because the abstraction layer is so extensive.

In terms of keeping a consistent look and feel: a) It's also possible to create a system of macros which render the HTML required for a particular field, e.g. "title", "description". In this way, creating a form for a content-type isn't really much work. b) Most systems have settled on a particular markup (Plone certainly has). Deviant forms can be normalized using Deliverance or other massaging (this may be suboptimal).

As Wichert mentions, you can build a layer on top of formapi (or the framework of your choice) for autogeneration. We did experiment with that, but it never materialized--probably we'd ran out of itches and by then were just guessing as to what we'd want from an autogeneration system.

Mcweekly said...

Very nice, clean and simple. I'll be using this in my next project for sure.

Is there an example anywhere or is it possible to use repoze.formapi for handling subforms / compound forms?

e.g. multiple phone numbers on a contact

contact:
title:
phone_numbers:
- type:
area_code:
prefix:
number:

malthe said...

@mcweekly: compound forms are not difficult; your example corresponds to the fields definition:

fields = {
'contact': {int: {
'title': unicode,
'phone_numbers': [str],
etc.}}

You then need to make sure that your HTML fields have corresponding names, e.g. name="contact.1.title" etc. using some unique numbering scheme.