Orderable formlib form fields

15 Feb

The zope.formlib is the form framework in Zope 3 that makes it easy to generate browser forms using Zope 3 schemas and perform validation on user input. This is of course something what we’ve come to expect using using existing tools like Archetypes schemas and CMFFormController. The good news about formlib is that you can already use it in Plone (and we do so extensively in the Plone 3 version of PrimaGIS).

One of the advantages of formlib is that you can easily take multiple schemas, throw them into a single form, select the fields that you want to include in the form and have formlib automatically handle the different schemas by adapting your content object accordingly when saving the data. Although formlib matches up very nicely to Archetypes generated forms (if you ignore the small amount of fields/widgets available for formlib compared to AT) there is one feature in Archetypes that does not exist in formlib: field reordering.

In Archetypes, you can take an Archetypes.Schema.Schema instance and reorder fields programmatically using the Schema.moveField() method, e.g.

>>> from Products.Archetypes.atapi import Schema, StringField
>>> schema = Schema((StringField('a'),
...                  StringField('b'),
...                  StringField('c')))
>>> schema.keys()
>>> schema.moveField('c', before='a')
>>> schema.keys()
>>> schema.moveField('a', pos='bottom')
>>> schema.keys()

Moving fields around is usually necessary when you’re (re)using an existing Schema defined somewhere else and wish to modify it for your own use. Having to define a new schema (by copying code) simply to get the form to display fields in a different order would feel like a waste of resources so having the ability (and a nice API) to modify existing schemas is useful.

For this reason I implemented an enhanced version of the zope.formlib.form.Fields class that supports reordering formlib fields using an API almost identical to the one in Archetypes. The package is called hexagonit.form and is available from the Cheeseshop.

To use the enhanced version, you simply use hexagonit.form.orderable.OrderableFields in place of zope.formlib.form.Fields in your code. Below is a dummy example demonstrating its use.

We first need to declare a simple schema for which the form will be generated.

>>> from zope.interface import Interface
>>> from zope.schema import TextLine, Bool, Int

>>> class ISomeSchema(Interface):
...     text = TextLine(title=u"text field")
...     boolean = Bool(title=u"boolean field")
...     integer = Int(title=u"integer field")

Now that we have a schema, we can generate the form fields using hexagonit.form.

>>> from hexagonit.form.orderable import OrderableFields
>>> form_fields = OrderableFields(ISomeSchema)

The form_fields variable now contains your normal formlib fields with the additional moveField method that allows reordering the fields on the fly.

>>> [field.__name__ for field in form_fields]
['text', 'boolean', 'integer']

>>> form_fields.moveField("boolean", direction="up")
>>> [field.__name__ for field in form_fields]
['boolean', 'text', 'integer']

>>> form_fields.moveField("boolean", position=2)
>>> [field.__name__ for field in form_fields]
['integer', 'text', 'boolean']

>>> form_fields.moveField('boolean', before='integer')
>>> [field.__name__ for field in form_fields]
['boolean', 'integer', 'text']

The moveField method allows reordering the form fields in a variety of ways using the different keyword parameters:

  • direction parameter with values “up” and “down” for changing the position of the field relative to its current position
  • position parameter with values “first” and “last” (or alternatively “top” and “bottom” ) or using absolute positions with integer values (first field at position 0) to place the field in a specific position
  • after and before parameters to place the field in a position relative to another field.

The doctests in the package describe the functionality of the moveField in full detail. An actual form implementation would look something like this in Plone:

from Products.Five.formlib import formbase
from hexagonit.form.orderable import OrderableFields
from somewhere import IMySchema, MyCustomWidget

class MyAddForm(formbase.AddFormBase):
    # Instantiate the form fields
    form_fields = OrderableFields(IMySchema)

    # All normal functionality of zope.formlib.form.Fields is
    # available, such as [field].custom_widget, .omit(), .select() etc.
    form_fields['somefield'].custom_widget = MyCustomWidget

    # After setting up the fields you can reorder them according
    # to your needs
    form_fields.moveField('somefield', position='last')
    form_fields.moveField('otherfield', direction='up')

    # Rest of form implementation follows..


The easiest way to install and try hexagonit.form is to use easy_install:

$ easy_install hexagonit.form

You can also manually download the egg or the source tarball from the Cheeseshop page.

1 Comment

Posted by on February 15, 2007 in plone, zope


One response to “Orderable formlib form fields

  1. Alex

    April 25, 2007 at 15:58

    Thank You


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: