Skip to main content

Tools to construct z3c.form forms

Project description

plone.autoform

This package provides tools to construct z3c.form forms out of hints stored in tagged values on schema interfaces. A special form base class is used to set up the fields and groups properties on form instances. It also contains a “display form” implementation that is compatible with Zope 2 page templates, and with some convenience features for rendering widgets in view mode.

The tagged values are stored under a various keys. These can be found in the plone.autoform.interfaces module. They support:

  • changing a field to ‘display’ or ‘hidden’ mode

  • omitting fields

  • re-ordering fields relative to one another

  • placing fields into fieldsets (groups)

  • changing the widget of a field

  • displaying a field conditionally based on a permission

There are several ways to set the form data:

  • Manually, by using setTaggedValue() on an interface.

  • By loading the schema from a plone.supermodel XML file and using the form: prefix

  • By using the directives from plone.autoform.directives while defining a schema in Python.

To use the automatic form setup, mix in the following base class in your forms:

>>> from plone.autoform.form import AutoExtensibleForm

and then provide the schema` (a schema interface) and optionally the additionalSchemata (a list of schema interfaces) attributes on your form:

>>> class MyForm(AutoExtensibleForm, form.EditForm):
...     schema = IMySchema
...     additionalSchemata = (ISchemaOne, ISchemaTwo,)
...
...     # ...

For dynamic forms, you could of course make schema and additionalSchemata into properties.

To use the display form, create a view like:

>>> from plone.autoform.view import WidgetsView
>>> class MyView(WidgetsView):
...     schema = IMySchema
...     additionalSchemata = (ISchemaOne, ISchemaTwo,)
...
...     # ...

To render the form, do not override __call__(). Instead, either implement the render() method, set an index attribute to a page template or other callable, or use the template attribute of the <browser:page /> ZCML directive when registering the view.

In the template, you can use the following variables:

  • view/w is a dictionary of all widgets, including those from non-default fieldsets (by contrast, the widgets variable contains only those widgets in the default fieldset). The keys are the field names, and the values are widget instances. To render a widget (in display mode), you can do tal:replace="structure view/w/myfield/render" />.

  • view/fieldsets is a dictionary of all fieldsets (not including the default fieldset, i.e. those widgets not placed into a fieldset). They keys are the fieldset names, and the values are the fieldset form instances, which in turn have variables like widgets given a list of all widgets.

See `autoform.txt` for details on how to use the form generation, view.txt for details on the widgets view, and supermodel.txt for information on the form XML namespace in a plone.supermodel schema file.

Form setup details

This package provides tools to construct z3c.form forms out of hints stored in tagged values on schema interfaces. A special form base class is used to set up the ‘fields’ and ‘groups’ properties on form instances.

The tagged values are stored under keys represented by the following constants:

>>> from plone.autoform.interfaces import OMITTED_KEY
>>> from plone.autoform.interfaces import WIDGETS_KEY
>>> from plone.autoform.interfaces import MODES_KEY
>>> from plone.autoform.interfaces import ORDER_KEY
>>> from plone.autoform.interfaces import READ_PERMISSIONS_KEY
>>> from plone.autoform.interfaces import WRITE_PERMISSIONS_KEY

In addition, field groups are constructed from plone.supermodel fieldsets, which are also stored in tagged values, under the following constant:

>>> from plone.supermodel.interfaces import FIELDSETS_KEY

There are several ways to set the form data:

  • Manually, by using setTaggedValue() on an interface.

  • By loading the schema from a plone.supermodel XML file. This package provides a schema handler for the ‘form’ prefix that can be used to incorporate form hints. See supermodel.txt for details.

  • By using the grok directives in the plone.directives.form package.

For the purposes of this test, we’ll set the form data manually.

Test setup

First, let’s load this package’s ZCML so that we can run the tests:
>>> configuration = """\
... <configure xmlns="http://namespaces.zope.org/zope">
...
...     <include package="Products.Five" file="configure.zcml" />
...     <include package="plone.autoform" />
...
... </configure>
... """
>>> from StringIO import StringIO
>>> from zope.configuration import xmlconfig
>>> xmlconfig.xmlconfig(StringIO(configuration))

We also need a few sample interfaces:

>>> from zope.interface import Interface
>>> from zope import schema
>>> class ITestSchema(Interface):
...     one = schema.TextLine(title=u"One")
...     two = schema.TextLine(title=u"Two")
...     three = schema.TextLine(title=u"Three")
...     four = schema.TextLine(title=u"Four")
...     five = schema.TextLine(title=u"Five")
...     six = schema.TextLine(title=u"Six")
>>> class ISupplementarySchema(Interface):
...     one = schema.TextLine(title=u"One")
...     two = schema.TextLine(title=u"Two")
>>> class IOtherSchema(Interface):
...     three = schema.TextLine(title=u"Three")
...     four = schema.TextLine(title=u"Four")
...     five = schema.TextLine(title=u"Five")
...     six = schema.TextLine(title=u"Six")

And a test context and request, marked with the IFormLayer interface to make z3c.form happy:

>>> from zope.publisher.browser import TestRequest
>>> from z3c.form.interfaces import IFormLayer
>>> context = object()
>>> request = TestRequest(environ={'AUTHENTICATED_USER': 'user1'}, skin=IFormLayer)

Note that we need to pretend that we have authenticated a user. Without this, the permission checks will be turned off. This is to support setting up a form pre-traversal in the ++widget++ namespace in plone.z3cform.

And finally, a form:

>>> from z3c.form.interfaces import IForm, IEditForm
>>> from plone.autoform.form import AutoExtensibleForm
>>> from z3c.form import form, button
>>> class TestForm(AutoExtensibleForm, form.Form):
...     schema = ITestSchema
...     additionalSchemata = (ISupplementarySchema, IOtherSchema,)
...
...     ignoreContext = True

This form is in input mode:

>>> TestForm.mode
'input'

Adding form data

Form data can be held under the following keys:

OMITTED_KEY – A list of (interface, fieldName, boolean) triples. If the

third value evaluates to true, the field with the given fieldName will be omitted from forms providing the given interface.

MODES_KEY – A list of (interface, fieldName, mode string) triples. A mode

string may be one of the z3c.form widget modes, including ‘hidden’, ‘input’, and ‘display’. The field will be rendered using a widget in the specified mode on forms providing the given interface.

WIDGETS_KEY – A dict of fieldName => widget. The widget can be

the dotted name of a z3c.form field widget factory, or an actual instance of one.

ORDER_KEY – A list of (fieldName, direction, relative_to) triples.

direction can be one of ‘before’ or ‘after’. relative_to can be ‘*’ (any/all fields), or the name of a field to move the given field before or after in the form.

READ_PERMISSIONS_KEY – A dict of fieldName => permission id. When a

form is in ‘display’ mode, the field will be omitted unless the user has the given permission in the form’s context. The permission id should be a Zope 3 style IPermission utility name, not a Zope 2 permission string.

WRITE_PERMISSIONS_KEY – A dict of fieldName => permission id. When a

form is in ‘input’ mode, the field will be omitted unless the user has the given permission in the form’s context. The permission id should be a Zope 3 style IPermission utility name, not a Zope 2 permission string.

Note that ‘order’ directives are processed after all schemata in the form are set up. Ordering will start by going through the additionalSchemata in order. The form’s base schema is processed last.

This means that the last ordering directive to be run is the last item in the list in the form’s base schema. Hence, this can be used to override any ordering information from additional schemata.

The fieldName should never contain a prefix or a dot. However, the relative_to name under ORDER_KEY should contain a prefixed name. The default form schema will not have a prefix, but additional schemata will have a prefix constructed from their __identifier__ (full dotted name). To explicitly reference a field in the current schema (or a base schema), use a leading dot, e.g. “.title” would refer to the “title” field in the current schema, whereas “title” would refer to the “title” field in the form’s base schema.

Fieldset data is kept under the key defined in the constant FIELDSETS_KEY. This contains a list of plone.supermodel.model.Fieldset instances.

At this point, there is no form data. When the form is updated, the ‘fields’ and ‘groups’ properties will be set.

>>> test_form = TestForm(context, request)
>>> test_form.update()
>>> test_form.fields.keys()
['one', 'two', 'three', 'four', 'five', 'six',
 'ISupplementarySchema.one', 'ISupplementarySchema.two',
 'IOtherSchema.three', 'IOtherSchema.four', 'IOtherSchema.five', 'IOtherSchema.six']
>>> test_form.groups
()

Note how we have all the fields from all the schemata, and that the fields from the additional schemata have been prefixed with the schema dotted name.

Let us now set up some form data.

Omitted fields are listed like this:

>>> ITestSchema.setTaggedValue(OMITTED_KEY,
...                            ((IForm, 'four', True),
...                             (Interface, 'four', False),
...                             (Interface, 'five', False),
...                             (Interface, 'five', True))
...                           )

Field modes can be set like this:

>>> ITestSchema.setTaggedValue(MODES_KEY,
...                            ((Interface, 'one', 'display'),
...                             (IEditForm, 'one', 'display'),
...                             (IForm, 'one', 'hidden'),
...                             (Interface, 'two', 'display'))
...                           )

Widgets can be specified either by a dotted name string or an actual instance:

>>> from z3c.form.browser.password import PasswordFieldWidget
>>> ITestSchema.setTaggedValue(WIDGETS_KEY, {'two': PasswordFieldWidget})
>>> IOtherSchema.setTaggedValue(WIDGETS_KEY, {'five': 'z3c.form.browser.password.PasswordFieldWidget'})

Fields can be moved like this:

>>> IOtherSchema.setTaggedValue(ORDER_KEY, [('four', 'before', 'ISupplementarySchema.one'),
...                                         ('five', 'after', '.six',)])
>>> ISupplementarySchema.setTaggedValue(ORDER_KEY, [('one', 'before', '*'),
...                                                 ('two', 'before', 'one')])
>>> ITestSchema.setTaggedValue(ORDER_KEY,          [('one', 'after', 'two')])

Note how the second value of each tuple refers to the full name with a prefix, so the field ‘two’ from ISupplementarySchema is moved before the field ‘one’ from the default (un-prefixed) ITestSchema. However, we move IOtherSchema’s field ‘five’ after the field ‘six’ in the same schema by using a shortcut: ‘.six’ is equivalent to ‘IOtherSchema.six’ in this case.

Field permissions can be set like this:

>>> ITestSchema.setTaggedValue(WRITE_PERMISSIONS_KEY, { 'five': u'dummy.PermissionOne',
...                                                      'six': u'five.ManageSite'})

Note that if a permission is not found, the field will be allowed.

Finally, fieldsets are configured like this:

>>> from plone.supermodel.model import Fieldset
>>> ITestSchema.setTaggedValue(FIELDSETS_KEY,
...                                 [Fieldset('fieldset1', fields=['three'],
...                                           label=u"Fieldset one",
...                                           description=u"Description of fieldset one")])
>>> IOtherSchema.setTaggedValue(FIELDSETS_KEY, [Fieldset('fieldset1', fields=['three'])])

Note how the label/description need only be specified once.

The results of all of this can be seen below:

>>> test_form = TestForm(context, request)
>>> test_form.update()
>>> test_form.fields.keys()
['IOtherSchema.four',
 'ISupplementarySchema.one',
 'ISupplementarySchema.two',
 'two',
 'one',
 'five',
 'IOtherSchema.six',
 'IOtherSchema.five']

The field ISupplementarySchema['one'] was moved to the top of the form, but then IOtherSchema['four'] was moved before this one again. ITestSchema['one'] was moved after ITestSchema['two']. ISupplementarySchema['two'] was then moved before ITestSchema['one'], coming between ITestSchema['one'] and ITestSchema['two'].

ITestSchema['one'] was hidden and ITestSchema['two'] was put into display mode:

>>> test_form.widgets['one'].mode
'hidden'
>>> test_form.widgets['two'].mode
'display'

ITestSchema['two'] and IOtherSchema['five'] were both given a password widget - one by instance, the other by dotted name:

>>> test_form.widgets['two']
<PasswordWidget 'form.widgets.two'>
>>> test_form.widgets['IOtherSchema.five']
<PasswordWidget 'form.widgets.IOtherSchema.five'>

There is one group corresponding to the fieldset where we put two fields. It has taken the label and description from the first definition.

>>> len(test_form.groups)
1
>>> test_form.groups[0].label
u'Fieldset one'
>>> test_form.groups[0].description
u'Description of fieldset one'
>>> test_form.groups[0].fields.keys()
['three', 'IOtherSchema.three']

Pre-traversal

plone.z3cform installs a ++widget++ namespace to allow traversal to widgets. Unfortunately, traversal happens before authentication. Thus, all security checks (read/write permissions) will fail.

To work around this, we ignore security checks if no authenticated user is set in the request. Previously, we added one to the test request. If we run the same tests without an authenticated user, the field ‘six’ should return.

>>> request = TestRequest(skin=IFormLayer)
>>> test_form = TestForm(context, request)
>>> test_form.update()
>>> test_form.fields.keys()
['IOtherSchema.four',
 'ISupplementarySchema.one',
 'ISupplementarySchema.two',
 'two',
 'one',
 'five',
 'six',
 'IOtherSchema.six',
 'IOtherSchema.five']

Automatic field sets

It is possible to create fieldsets automatically, on the principle of one fieldset per schema. In this case, the fieldset name is the schema name, the schema docstring becomes the schema description, and all fields in that schema that are not explicitly assigned to another fieldset, will be in the the per-schema fieldset.

>>> class Basics(Interface):
...     """Basic metadata"""
...     title = schema.TextLine(title=u"Title")
...     description = schema.TextLine(title=u"Description")
...     creation_date = schema.Date(title=u"Creation date")
...     hidden_secret = schema.TextLine(title=u"Hidden secret!")

Let’s change some field settings to ensure that they are still processed, and move the creation_date field to another fieldset, which we will define in full.

>>> Basics.setTaggedValue(MODES_KEY, [(Interface, 'hidden_secret', 'hidden')])
>>> Basics.setTaggedValue(FIELDSETS_KEY, [Fieldset('Dates', label="Cool dates", fields=['creation_date'])])
>>> class Dates(Interface):
...     """Date information"""
...     start_date = schema.Date(title=u"Start date")
...     end_date = schema.Date(title=u"End date")
>>> class Ownership(Interface):
...     """Ownership information"""
...     owner = schema.Date(title=u"The owner")

We can make a form of these schemata. For the sake of this demo, we’ll also set ignorePrefix to true, so that the form fields don’t get a prefix. Note that this may cause clashes if fields in different schemata share a name.

>>> class CombiForm(AutoExtensibleForm, form.Form):
...     schema = Basics
...     additionalSchemata = (Dates, Ownership,)
...
...     ignoreContext = True
...     ignorePrefix = True
...     autoGroups = True
>>> combi_form = CombiForm(context, request)
>>> combi_form.update()

The default fields are those from the base schema, minus the one moved to another fieldset.

>>> combi_form.fields.keys()
['title', 'description', 'hidden_secret']
>>> combi_form.widgets['hidden_secret'].mode
'hidden'

Each additional schema then has its own fields. Note that setting the ‘dates’ fieldset in the base schema had the effect of giving a more specific label to the automatically created group for the Dates schema.

>>> [(g.__name__, g.label, g.description, g.fields.keys(),) for g in combi_form.groups]
[('Dates', 'Cool dates', None, ['creation_date', 'start_date', 'end_date']),
 ('Ownership', 'Ownership', 'Ownership information', ['owner'])]

Widget-aware views

This package provides a view mixin class that can be used like a display form. The view is set up with widgets based on schema interfaces and/or form fields, and are available in ‘display’ mode.

First, let’s load this package’s ZCML so that we can run the tests:

>>> configuration = """\
... <configure xmlns="http://namespaces.zope.org/zope">
...
...     <include package="Products.Five" file="configure.zcml" />
...     <include package="plone.autoform" />
...
... </configure>
... """
>>> from StringIO import StringIO
>>> from zope.configuration import xmlconfig
>>> xmlconfig.xmlconfig(StringIO(configuration))

As with auto-forms, the widgets come from a primary schema interface, and optionally one or more secondary interfaces. Let’s define two.

>>> from zope.interface import Interface
>>> from zope import schema
>>> class IDefaultSchema(Interface):
...     title = schema.TextLine(title=u"Title")
...     body = schema.Text(title=u"Body")
>>> class ISecondarySchema(Interface):
...     summary = schema.Text(title=u"Summary")

Let us also annotate these with some field hints, putting ‘summary’ into a secondary schema.

>>> from plone.supermodel.interfaces import FIELDSETS_KEY
>>> from plone.supermodel.model import Fieldset
>>> ISecondarySchema.setTaggedValue(FIELDSETS_KEY, [Fieldset('secondary', fields=['summary'])])

A display form normally operates on a given context, although you could set ignoreContext = True and/or implement getContent() if applicable. The schema interfaces need to be provided by or adaptable from the context. For the purposes of this test, we’ll just make them directly provided.

>>> from zope.interface import implements
>>> class Context(object):
...     implements(IDefaultSchema, ISecondarySchema)
...     title = u""
...     body = u""
...     summary = u""

We can now define a display form view. This should sub class or mix in WidgetsView. It must define either an index callable (usually a page template set by the <browser:page /> directive) or override the render method. It should also set the schema and additionalSchemata properties as required, using class variables, instance variables or properties.

>>> from plone.autoform.view import WidgetsView
>>> class TestView(WidgetsView):
...     schema = IDefaultSchema
...     additionalSchemata = (ISecondarySchema,)
...     def render(self):
...         return u"<div>My title widget says %s</div>" % self.w['title'].render()

Let us try to render this, to demonstrate that the widgets will be properly set up.

>>> from z3c.form.testing import TestRequest
>>> context = Context()
>>> request = TestRequest()
>>> context.title = u"Test title"
>>> context.body = u"Body"
>>> context.summary = u"Summary"
>>> view = TestView(context, request)
>>> print view()
<div>My title widget says <span id="form-widgets-title"
      class="text-widget required textline-field">Test title</span>
</div>

More generally, the view supports the contract of display forms. After being updated, we have access to widgets in the default fieldset:

>>> view.widgets.items()
[('title', <TextWidget 'form.widgets.title'>),
 ('body', <TextAreaWidget 'form.widgets.body'>)]

There is also a shortcut to allow access to any widget by (possibly prefixed) name:

>>> view.w.items()
[('body', <TextAreaWidget 'form.widgets.body'>),
 ('ISecondarySchema.summary', <TextAreaWidget 'form.widgets.ISecondarySchema.summary'>),
 ('title', <TextWidget 'form.widgets.title'>)]

You can also see fieldsets (groups) either in order:

>>> view.groups
(<plone.z3cform.fieldsets.group.Group object at ...>,)

or looked up by name:

>>> view.fieldsets.items()
[('secondary', <plone.z3cform.fieldsets.group.Group object at ...>)]

Note how the schema name is used as a prefix to all additional schemata. If you wish to flatten the namespace, you can set ignorePrefix to true:

>>> view = TestView(context, request)
>>> view.ignorePrefix = True
>>> view.update()
>>> view.w.items()
[('body', <TextAreaWidget 'form.widgets.body'>),
 ('summary', <TextAreaWidget 'form.widgets.summary'>),
 ('title', <TextWidget 'form.widgets.title'>)]

For supporting widget traversal it is necessary that after updating the form the widgets are present:

>>> view2 = TestView(context, request)
>>> view2.update()
>>> view2.widgets
<z3c.form.field.FieldWidgets object at ...>
>>> view2.widgets.keys()
['title', 'body']

Supermodel handlers

This package contains handlers for two plone.supermodel namespaces: form, which can be used to set widgets, omitted fields, field modes and field order, and security, which can be used to set field read and write permissions.

Test setup

First, let’s load this package’s ZCML so that we can run the tests:

>>> configuration = """\
... <configure xmlns="http://namespaces.zope.org/zope">
...
...     <include package="Products.Five" file="configure.zcml" />
...     <include package="plone.autoform" />
...
... </configure>
... """
>>> from StringIO import StringIO
>>> from zope.configuration import xmlconfig
>>> xmlconfig.xmlconfig(StringIO(configuration))

XML sample

Next, let’s define a sample model that exercises the various form and security attributes.

>>> schema = """\
... <?xml version="1.0" encoding="UTF-8"?>
... <model xmlns="http://namespaces.plone.org/supermodel/schema"
...        xmlns:form="http://namespaces.plone.org/supermodel/form"
...        xmlns:security="http://namespaces.plone.org/supermodel/security">
...     <schema>
...         <field type="zope.schema.TextLine" name="one"
...                 form:omitted="true"
...                 form:after="two"
...                 security:read-permission="zope2.View"
...                 security:write-permission="cmf.ModifyPortalContent">
...             <title>One</title>
...         </field>
...         <field type="zope.schema.TextLine" name="two"
...                form:mode="hidden">
...             <title>Two</title>
...         </field>
...         <field type="zope.schema.TextLine" name="three"
...                 form:before="two"
...                 form:widget="z3c.form.browser.password.PasswordFieldWidget"
...                 form:validator="plone.autoform.tests.test_utils.TestValidator"
...                 form:omitted="z3c.form.interfaces.IForm:true z3c.form.interfaces.IEditForm:false"
...                 form:mode="z3c.form.interfaces.IEditForm:input">
...             <title>Three</title>
...         </field>
...     </schema>
... </model>
... """

Notes:

  • To omit a field from all forms, use form:omitted="true". To omit a field only from some forms, specify a form interface like form:omitted="z3c.form.interfaces.IForm:true". Multiple interface:value settings may be specified, separated by spaces.

  • To re-order fields, use form:after or form:before. The value should be either '*', to put the field first/last in the form, or the name of a another field. Use '.fieldname' to refer to field in the current schema (or a base schema). Use a fully prefixed name (e.g. 'my.package.ISomeSchema') to refer to a field in another schema. Use an unprefixed name to refer to a field in the default schema for the form.

  • To turn a field into a view mode or hidden field, use form:mode. The mode may be set for only some forms by specifying a form interface in the same manner as for form:omitted.

  • To set a custom widget for a field, use form:widget to give a fully qualified name to the field widget factory.

  • To set a custom validator for a field, use form:validator to give a fully qualified name to the field validator factory.

  • To set a read or write permission, use security:read-permission or security:write-permission. The value should be the name of an IPermission utility.

We can load this using plone.supermodel:

>>> from plone.supermodel import loadString
>>> model = loadString(schema)

The interface defined in the model should now have the relevant form data:

>>> from plone.autoform.interfaces import OMITTED_KEY, WIDGETS_KEY, \
...     MODES_KEY, ORDER_KEY, READ_PERMISSIONS_KEY, WRITE_PERMISSIONS_KEY
>>> model.schema.getTaggedValue(WIDGETS_KEY)
{'three': 'z3c.form.browser.password.PasswordFieldWidget'}
>>> model.schema.getTaggedValue(OMITTED_KEY)
[(<InterfaceClass zope.interface.Interface>, 'one', 'true'), (<InterfaceClass z3c.form.interfaces.IForm>, 'three', 'true'), (<InterfaceClass z3c.form.interfaces.IEditForm>, 'three', 'false')]
>>> model.schema.getTaggedValue(ORDER_KEY)
[('one', 'after', 'two'), ('three', 'before', 'two')]
>>> model.schema.getTaggedValue(MODES_KEY)
[(<InterfaceClass z3c.form.interfaces.IEditForm>, 'three', 'input'), (<InterfaceClass zope.interface.Interface>, 'two', 'hidden')]
>>> model.schema.getTaggedValue(READ_PERMISSIONS_KEY)
{'one': 'zope2.View'}
>>> model.schema.getTaggedValue(WRITE_PERMISSIONS_KEY)
{'one': 'cmf.ModifyPortalContent'}

See autoform.txt for details on how this form data is used to manipulate form layout.

Form directives

In addition to using XML, the tagged values used to control autoform’s behavior can instead be set up using “directives” called while defining a schema in Python.

Below is an example that exercises the various directives:

from z3c.form.interfaces import IEditForm
from plone.supermodel import model
from plone.autoform import directives as form
from plone.app.z3cform.wysiwyg import WysiwygFieldWidget

class IMySchema(model.Schema):

    # Add a new fieldset and put the 'footer' and 'dummy' fields in it.
    # If the same fieldset is defined multiple times, the definitions
    # will be merged, with the label from the first fieldset taking
    # precedence.

    model.fieldset('extra',
            label=u"Extra info",
            fields=['footer', 'dummy']
        )

    title = schema.TextLine(
            title=u"Title"
        )

    summary = schema.Text(
            title=u"Summary",
            description=u"Summary of the body",
            readonly=True
        )

    form.widget(body='plone.app.z3cform.wysiwyg.WysiwygFieldWidget')
    model.primary('body')
    body = schema.Text(
            title=u"Body text",
            required=False,
            default=u"Body text goes here"
        )


    form.widget(footer=WysiwygFieldWidget)
    footer = schema.Text(
            title=u"Footer text",
            required=False
        )

    form.omitted('dummy')
    dummy = schema.Text(
            title=u"Dummy"
        )

    form.omitted('edit_only')
    form.no_omit(IEditForm, 'edit_only')
    edit_only = schema.TextLine(
            title = u'Only included on edit forms',
        )

    form.mode(secret='hidden')
    form.mode(IEditForm, secret='input')
    secret = schema.TextLine(
            title=u"Secret",
            default=u"Secret stuff (except on edit forms)"
        )

    form.order_before(not_last='summary')
    not_last = schema.TextLine(
            title=u"Not last",
        )

Here, we have placed the directives immediately before the fields they affect, but they could be placed anywhere in the interface body. All the directives can take multiple values, usually in the form fieldname='value'.

The omitted(), no_omit, and primary() directives take a list of field names instead. The widget() directive allows widgets to be set either as a dotted name, or using an imported field widget factory. The order_before() directive has a corresponding order_after() directive.

Changelog

1.2 (2012-04-15)

  • Moved form schema directives here from plone.directives.form, and reimplemented them as plone.supermodel directives to avoid depending on grok. Included directives: omitted, no_omit, mode, widget, order_before, order_after, read_permission, write_permission [davisagli]

1.1 - 2012-02-20

  • Added the AutoObjectSubForm class to support form hints for object widget subforms. [jcbrand]

1.0 - 2011-05-13

  • Raise a NotImplementedError instead of NotImplemented as that is not an exception but meant for comparisons and is not callable. [maurits]

1.0b7 - 2011-04-29

  • Check to make sure that interfaces and field widgets resolved by the supermodel handler are of the correct type. [elro]

  • Add form:validator support for supermodel. [elro]

  • Fix issue where permission checks were not applied correctly to schemas being added with prefixes. [davisagli]

  • Add MANIFEST.in. [WouterVH]

1.0b6 - 2011-02-11

  • Fix WidgetsView so that _update and update do not clash. [elro]

  • Fix view.txt doctest to test actual behaviour, not artifacts from test setup. [elro]

1.0b5 - 2011-01-11

  • Use five.ManageSite permission to check field permissions. We’ll avoid sniffing for Five/CMFCore permissions.zcml difference between Zope 2.12 and 2.13. [esteele]

1.0b4 - 2010-08-05

1.0b3 - 2010-04-20

  • Properly handle the ‘omitted’ tagged value when it is set to ‘false’ for a field. [davisagli]

  • Make it possible to set the ‘omitted’ and ‘mode’ settings only for particular form interfaces. [davisagli]

  • Do not omit read-only fields when rendering a form in DISPLAY mode. http://code.google.com/p/dexterity/issues/detail?id=118 [mj]

1.0b2 - 2009-07-12

  • Changed API methods and arguments to mixedCase to be more consistent with the rest of Zope. This is a non-backwards-compatible change. Our profuse apologies, but it’s now or never. :-/

    If you find that you get import errors or unknown keyword arguments in your code, please change names from foo_bar too fooBar, e.g. process_fields() becomes processFields().

    Note in particular that the additional_schemata property is now called additionalSchemata. If you have implemented this property yourself, you will need to rename it! [optilude]

1.0b1 - 2009-04-17

  • Initial release

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

plone.autoform-1.2.zip (59.8 kB view hashes)

Uploaded Source

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page