The schema

by Martin Aspeli last modified Apr 26, 2010 10:08 PM
Writing a schema for the type

A simple Dexterity types consists of a schema and an FTI (Factory Type Information, the object configured in portal_types in the ZMI). We'll create the schemata here, and the FTI on the next page.

Each schema is typically in a separate module. Thus, we will add three files to our product: presenter.py, program.py, and session.py. Each will start off with a schema interface.

First, we will define a message factory to aid future internationalisation of the package. Every string that is presented to the user should be wrapped in _() as shown with the titles and descriptions below.

The message factory lives in the package root __init__.py file:

from zope.i18nmessageid import MessageFactory

_ = MessageFactory("example.conference")

Notice how we use the package name as the translation domain.

We can now define the schemata for our three types.

For the Presenter type, presenter.py looks like this:

from five import grok
from zope import schema

from plone.directives import form, dexterity

from plone.app.textfield import RichText
from plone.namedfile.field import NamedImage

from example.conference import _

class IPresenter(form.Schema):
    """A conference presenter. Presenters can be added anywhere.
    """
    
    title = schema.TextLine(
            title=_(u"Name"),
        )
    
    description = schema.Text(
            title=_(u"A short summary"),
        )
    
    bio = RichText(
            title=_(u"Bio"),
            required=False
        )
    
    picture = NamedImage(
            title=_(u"Picture"),
            description=_(u"Please upload an image"),
            required=False,
        )

Notice how we use the field names title and description for the name and summary. We do this to provide values for the default title and description metadata used in Plone's folder listings and searches, which defaults to these fields. In general, every type should have a title field, although it could be provided by behaviors (more on those later).

For the Program type, program.py looks like this:

from five import grok
from zope import schema

from plone.directives import form, dexterity
from plone.app.textfield import RichText

from example.conference import _

class IProgram(form.Schema):
    """A conference program. Programs can contain Sessions.
    """
    
    title = schema.TextLine(
            title=_(u"Program name"),
        )
    
    description = schema.Text(
            title=_(u"Program summary"),
        )
    
    start = schema.Datetime(
            title=_(u"Start date"),
            required=False,
        )

    end = schema.Datetime(
            title=_(u"End date"),
            required=False,
        )
    
    details = RichText(
            title=_(u"Details"),
            description=_(u"Details about the program"),
            required=False,
        )

Finally, session.py for the Session type looks like this:

from five import grok
from zope import schema

from plone.directives import form, dexterity
from plone.app.textfield import RichText

class ISession(form.Schema):
    """A conference session. Sessions are managed inside Programs.
    """
    
    title = schema.TextLine(
            title=_(u"Title"),
            description=_(u"Session title"),
        )
    
    description = schema.Text(
            title=_(u"Session summary"),
        )
    
    details = RichText(
            title=_(u"Session details"),
            required=False
        )

Note that we haven't added information about speakers or tracks yet. We'll do that when we cover vocabularies and references later.

Schema interfaces vs. other interfaces

As you may have noticed, each schema is basically just an interface (zope.interface.Interface) with fields. The standard fields are found in the zope.schema package. You should look at its interfaces (parts/omelette/zope/schema/interfaces.py) to learn about the various schema fields available, and review the online documentation for the package. You may also want to look up plone.namedfile, which you can use if you require a file field, z3c.relationfield, which can be used for references, and plone.app.textfield, which supports rich text with a WYSIWYG editor. We will cover these field types later in this manual. They can also be found in the reference at the end.

Unlike a standard interface, however, we are deriving from form.Schema (actually, plone.directives.form.Schema). This is just a marker interface that allows us to add some form hints to the interface, which are then used by Dexterity (actually, the plone.autoform package) to construct forms. Take a look at the plone.directives.form documentation to learn more about the various hints that are possible. The most common ones are form.fieldset(), to define groups of fields, form.widget(), to set a widget for a particular field, and form.omit() to hide one or more fields from the form. We will see examples of these later in the manual.