| Location: | Plone Conference 2008, Washington, DC |
|---|---|
| Date: | October 10, 2008 |
| Presenter: | Stephan Richter, Keas Inc. |
Mastering the digital bureaucracy perferctly.
Read the freaking manual! (409kB ~ 400 pages)
Install, run and study z3c.formdemo:
$ svn co svn://svn.zope.org/repos/main/z3c.formdemo/trunk formdemo $ cd formdemo $ python bootstrap.py $ ./bin/buildout -N $ ./bin/demo fg
Ask a question if something is unclear
Juuuussttt kidding!
Today you have the choice between:
or
Form automation is an extremely viable part in making Zope 3 a high-productivity environment. In fact, the implementation presented in this session is already the third generation of form machinery. Older versions are still available in zope.app.form and zope.formlib but is not used anymore other than in legacy code.
If the UI requirements are consistent enough, it is sufficient to use one generic template for all or most forms. In my experience, however, this has not been the case and I have always ended up writing templates for each form. With enough helper functions this is commonly a quick task and does not represent a significant amount of the development time.
Fields represent attributes/properties in the form
See z3c.form.field
Extend schema fields with form-specific information (name prefixes, editability, custom widget, etc.)
(Form) fields are the traffickers between the form, schema field, and widget
An API exists to selectively choose fields of a schema to become form fields
Schemas are just interfaces:
Selecting all fields of a schema:
Selecting only a limited set of fields or changing the order:
Omitting a particular field:
Combining fields from different schemas:
I have never needed this feature. :-)
Represent an input method in a particular user interface, for example a "text" input in HTML forms
Presentation component of a schema field (field widget)
See z3c.form.widget and z3c.form.browser
Modes determine whether a display, edit or hidden widget is displayed
In contrast to previous widget implementations, the z3c.form package's widgets are very simple and are only respsonsible for ensuring the correct rendering in the output media, in our case most often HTML forms.
Converters are used to convert internal or field values to widget-processable values
For example, if we want to edit an integer in a standard text input, then it has to be converted to a string, since this is the only value type the widget knows how to process. So 1200.67 might be converted to "1,200.67".
Validators are used to validate submitted input
Validators can raise ValidationError errors which use ErrorViewSnippet presentation components to render themselves
Data Managers are used to store a value to a content component
In older form implementations, forms were only able to store field values into instances. Providing the abstraction of a data manager, allows us to store submitted data in other types of components, such as dictionaries.

Defines actions of a form
See z3c.form.button
Simple extension to schema fields
Conditions determine the availability of a button
Many ways to create buttons
A form can have multiple sets of button sets
Buttons as schema fields:
Single buttons within the form:
Declaring buttons via decorators:
Copy buttons, actions and handlers from the super-form:
It is fairly common to extend a form super-class. This is needed when the sub-class wants to define/override additional buttons, actions or handlers. others. If any of the three component collections are not copied, the assignment will override the collections in the super-class, which in turn affects all sub-classes, not just thw current one.
To keep matters simple within the form package, those forms do not directly proivde the correct APIs for advanced UI patterns such as viewlets and view templates. However, the overhead to make them work well with those pattersn is very small and a common base class is quickly developed.

Declarations made in ZCML:
These directives effectively define the setup of the checker for the class. The zope:allow and zope:require directives are used to define the get- and set-permissions needed for accessing each attribute. If no permission is assigned to an attribute getter/setter, then the attribute is unavailable to all while the component is security proxied.
ZCML directives are well-documented in the API Docs at http://apidoc.zope.org
Create object with an initial set of data
Validate data before object is created
IAdding components not directly supported, but support exists
See z3c.form.adding.AddForm
IAdding is a component designed to control the process of adding a new content component to a container. It controls the object to be created and the name that is given. The Adding component was originally developed for CMS-like applications, but it turns out that it is a lot of overhead for non-CMS sites. Thus it is advisable to avoid the adding component in general.
Implementation:
As you can see, we only need to implement three simple methods. The create() method's job is to create a valid component from the data of the form and return it. Next, the add(object) method is responsible for adding the object -- usually to a contained. Part of its contract is that it chooses a valid name. The nextURL() method simply returns a path to redirect to.
Register form as a simple page of IFolder:
Note: We must create a custom skin so that registrations are included.
After restarting Zope 3, the add form should be available
There is no link in the ZMI, because no menu was registered
Since we skipped the overhead of IAdding, adding a menu item is hard, unfortunately. Note, however, that you will almost never use the ZMI to add objects, so filling the ZMI add menu is pretty pointless anyways.
z3c.form was written with pagelets in mind. Since we want to keep the example as self-contained as possible, we are not using pagelets, which means that we have to define our own form templates. The div-form.css CSS resource and the form macro are registered in the IDivFormLayer layer.
Framework allows us to create custom attribute values for several widget attributes
Make today's date the default for the when field
A simple adapter to register
Note that the name of the adapter must be the name of the attribute that we are providing the value for.
While writing display forms every time you want to present a value might seem tedious at first, but it is worth the discipline. Otherwise you will eventually have unwanted presentation bugs. Common base classes can easily be created to make this a very trivial part of the development.
The Python view class:
The page template using the widgets:
Registering the display view:
To add an entry to the tabs, add the following to the page directive:
Edit forms are great, because their scope is limited and they can be easily used within other presentation components, allowing you to implement many interesting patterns.
An edit form with an additional custom button that switches back to the display view after saving the changes.
In this case we are using an existing action and just extend it. The existing "Apply" action saves the data, but also remains in the edit view. Our new action, "Apply and View", saves the data, but forwards the user to the view page.
Register form as a simple page of IHelloWorldMessage:
After restarting Zope 3, the edit form should be available
Add to tabs, add the following to the page directive: