34. Dexterity: Reference – Mastering Plone 5 development

34. Dexterity: Reference#

This chapter documents all types fields, widgets, directives that you can use with dexterity.

34.1. Fields included in Plone#

This is a schema with examples for all field-types that are shipped with Plone by default. They are arranged in fieldsets:

Default

Textline, Text, Boolean, Richtext (html), Email

Number fields

Integer, Float

Date and time fields

Datetime, Date, Time, Timedelta

Choice and Multiple Choice fields

Choice, Choice with radio widget, Choice with Select2 widget, Choice with named vocabulary, List, List with checkboxes, List with Select2 widget, List with values from named vocabulary but open to additions, Tuple, Set, Set with checkboxes

Relation fields

Relationchoice, Relationlist

File fields

File, Image

Other fields

Uri, Sourcetext, Ascii, Bytesline, Asciiline, Pythonidentifier, Dottedname, Dict, Dict with Choice

  1# -*- coding: utf-8 -*-
  2from plone.app.multilingual.browser.interfaces import make_relation_root_path
  3from plone.app.textfield import RichText
  4from plone.app.z3cform.widget import AjaxSelectFieldWidget
  5from plone.app.z3cform.widget import RelatedItemsFieldWidget
  6from plone.app.z3cform.widget import SelectFieldWidget
  7from plone.autoform import directives
  8from plone.dexterity.content import Container
  9from plone.namedfile.field import NamedBlobFile
 10from plone.namedfile.field import NamedBlobImage
 11from plone.schema.email import Email
 12from plone.supermodel import model
 13from plone.supermodel.directives import fieldset
 14from plone.supermodel.directives import primary
 15from ploneconf.site import _
 16from z3c.form.browser.checkbox import CheckBoxFieldWidget
 17from z3c.form.browser.radio import RadioFieldWidget
 18from z3c.relationfield.schema import Relation
 19from z3c.relationfield.schema import RelationChoice
 20from z3c.relationfield.schema import RelationList
 21from zope import schema
 22from zope.interface import implementer
 23
 24
 25class IExample(model.Schema):
 26    """Dexterity-Schema with all field-types."""
 27
 28    # The most used fields
 29    # textline, text, bool, richtext, email
 30
 31
 32    fieldset(
 33        'numberfields',
 34        label=u'Number fields',
 35        fields=('int_field', 'float_field'),
 36    )
 37
 38    fieldset(
 39        'datetimefields',
 40        label=u'Date and time fields',
 41        fields=('datetime_field', 'date_field', 'time_field', 'timedelta_field'),
 42    )
 43
 44    fieldset(
 45        'choicefields',
 46        label=u'Choice and Multiple Choice fields',
 47        fields=(
 48            'choice_field',
 49            'choice_field_radio',
 50            'choice_field_select',
 51            'choice_field_voc',
 52            'list_field',
 53            'list_field_checkbox',
 54            'list_field_select',
 55            'list_field_voc_unconstrained',
 56            'tuple_field',
 57            'set_field',
 58            'set_field_checkbox',
 59        ),
 60    )
 61
 62    fieldset(
 63        'relationfields',
 64        label=u'Relation fields',
 65        fields=('relationchoice_field', 'relationlist_field'),
 66    )
 67
 68    fieldset(
 69        'filefields',
 70        label=u'File fields',
 71        fields=('file_field', 'image_field'),
 72    )
 73
 74    fieldset(
 75        'otherfields',
 76        label=u'Other fields',
 77        fields=(
 78            'uri_field',
 79            'sourcetext_field',
 80            'ascii_field',
 81            'bytesline_field',
 82            'asciiline_field',
 83            'pythonidentifier_field',
 84            'dottedname_field',
 85            'dict_field',
 86            'dict_field_with_choice',
 87            ),
 88    )
 89
 90    primary('title')
 91    title = schema.TextLine(
 92        title=u'Primary Field (Textline)',
 93        required=True,
 94        )
 95
 96    text_field = schema.Text(
 97        title=u'Text Field',
 98        required=False,
 99        missing_value=u'',
100    )
101
102    textline_field = schema.TextLine(
103        title=u'Textline field',
104        description=u'A simple input field',
105        required=False,
106        )
107
108    bool_field = schema.Bool(
109        title=u'Boolean field',
110        required=False,
111    )
112
113    choice_field = schema.Choice(
114        title=u'Choice field',
115        values=[u'One', u'Two', u'Three'],
116        required=True,
117        )
118
119    directives.widget(choice_field_radio=RadioFieldWidget)
120    choice_field_radio = schema.Choice(
121        title=u'Choice field with radio boxes',
122        values=[u'One', u'Two', u'Three'],
123        required=True,
124        )
125
126    choice_field_voc = schema.Choice(
127        title=u'Choicefield with values from named vocabulary',
128        vocabulary='plone.app.vocabularies.PortalTypes',
129        required=False,
130        )
131
132    directives.widget(choice_field_select=SelectFieldWidget)
133    choice_field_select = schema.Choice(
134        title=u'Choicefield with select2 widget',
135        vocabulary='plone.app.vocabularies.PortalTypes',
136        required=False,
137        )
138
139    list_field = schema.List(
140        title=u'List field',
141        value_type=schema.Choice(
142            values=[u'Beginner', u'Advanced', u'Professional'],
143            ),
144        required=False,
145        missing_value=[],
146        )
147
148    directives.widget(list_field_checkbox=CheckBoxFieldWidget)
149    list_field_checkbox = schema.List(
150        title=u'List field with checkboxes',
151        value_type=schema.Choice(
152            values=[u'Beginner', u'Advanced', u'Professional'],
153            ),
154        required=False,
155        missing_value=[],
156        )
157
158    directives.widget(list_field_select=SelectFieldWidget)
159    list_field_select = schema.List(
160        title=u'List field with select widget',
161        value_type=schema.Choice(
162            values=[u'Beginner', u'Advanced', u'Professional'],
163            ),
164        required=False,
165        missing_value=[],
166        )
167
168    list_field_voc_unconstrained = schema.List(
169        title=u'List field with values from vocabulary but not constrained to them.',
170        value_type=schema.TextLine(),
171        required=False,
172        missing_value=[],
173        )
174    directives.widget(
175        'list_field_voc_unconstrained',
176        AjaxSelectFieldWidget,
177        vocabulary='plone.app.vocabularies.Users'
178    )
179
180
181    tuple_field = schema.Tuple(
182        title=u'Tuple field',
183        value_type=schema.Choice(
184            values=[u'Beginner', u'Advanced', u'Professional'],
185            ),
186        required=False,
187        missing_value=(),
188        )
189
190    set_field = schema.Set(
191        title=u'Set field',
192        value_type=schema.Choice(
193            values=[u'Beginner', u'Advanced', u'Professional'],
194            ),
195        required=False,
196        missing_value={},
197        )
198
199    directives.widget(set_field_checkbox=CheckBoxFieldWidget)
200    set_field_checkbox = schema.Set(
201        title=u'Set field with checkboxes',
202        value_type=schema.Choice(
203            values=[u'Beginner', u'Advanced', u'Professional'],
204            ),
205        required=False,
206        missing_value={},
207        )
208
209    # File fields
210    image_field = NamedBlobImage(
211        title=u'Image field',
212        description=u'A upload field for images',
213        required=False,
214        )
215
216    file_field = NamedBlobFile(
217        title=u'File field',
218        description=u'A upload field for files',
219        required=False,
220        )
221
222    # Date and Time fields
223    datetime_field = schema.Datetime(
224        title=u'Datetime field',
225        description=u'Uses a date and time picker',
226        required=False,
227    )
228
229    date_field = schema.Date(
230        title=u'Date field',
231        description=u'Uses a date picker',
232        required=False,
233    )
234
235    time_field = schema.Time(
236        title=u'Time field',
237        required=False,
238        )
239
240    timedelta_field = schema.Timedelta(
241        title=u'Timedelta field',
242        required=False,
243        )
244
245    # Relation Fields
246    relationchoice_field = RelationChoice(
247        title=u"Relationchoice field",
248        vocabulary='plone.app.vocabularies.Catalog',
249        required=False,
250    )
251    directives.widget(
252        "relationchoice_field",
253        RelatedItemsFieldWidget,
254        pattern_options={
255            "selectableTypes": ["Document"],
256            "basePath": make_relation_root_path,
257        },
258    )
259
260    relationlist_field = RelationList(
261        title=u"Relationlist Field",
262        default=[],
263        value_type=RelationChoice(vocabulary='plone.app.vocabularies.Catalog'),
264        required=False,
265        missing_value=[],
266    )
267    directives.widget(
268        "relationlist_field",
269        RelatedItemsFieldWidget,
270        vocabulary='plone.app.vocabularies.Catalog',
271        pattern_options={
272            "selectableTypes": ["Document"],
273            "basePath": make_relation_root_path,
274        },
275    )
276
277    # Number fields
278    int_field = schema.Int(
279        title=u"Integer Field (e.g. 12)",
280        description=u"Allocated (maximum) number of objects",
281        required=False,
282    )
283
284    float_field = schema.Float(
285        title=u"Float field (e.g. 12.2)",
286        required=False,
287    )
288
289    # Text fields
290    email_field = Email(
291        title=u'Email field',
292        description=u'A simple input field for a email',
293        required=False,
294        )
295
296    uri_field = schema.URI(
297        title=u'URI field',
298        description=u'A simple input field for a URLs',
299        required=False,
300        )
301
302    richtext_field = RichText(
303        title=u'RichText field',
304        description=u'This uses a richtext editor.',
305        max_length=2000,
306        required=False,
307        )
308
309    sourcetext_field = schema.SourceText(
310        title=u'SourceText field',
311        required=False,
312        )
313
314    ascii_field = schema.ASCII(
315        title=u'ASCII field',
316        required=False,
317        )
318
319    bytesline_field = schema.BytesLine(
320        title=u'BytesLine field',
321        required=False,
322        )
323
324    asciiline_field = schema.ASCIILine(
325        title=u'ASCIILine field',
326        required=False,
327        )
328
329    pythonidentifier_field = schema.PythonIdentifier(
330        title=u'PythonIdentifier field',
331        required=False,
332        )
333
334    dottedname_field = schema.DottedName(
335        title=u'DottedName field',
336        required=False,
337        )
338
339    dict_field = schema.Dict(
340        title=u'Dict field',
341        required=False,
342        key_type = schema.TextLine(
343            title=u'Key',
344            required=False,
345            ),
346        value_type = schema.TextLine(
347            title=u'Value',
348            required=False,
349            ),
350        )
351
352    dict_field_with_choice = schema.Dict(
353        title=u'Dict field with key and value as choice',
354        required=False,
355        key_type = schema.Choice(
356            title=u'Key',
357            values=[u'One', u'Two', u'Three'],
358            required=False,
359            ),
360        value_type = schema.Set(
361            title=u'Value',
362            value_type=schema.Choice(
363                values=[u'Beginner', u'Advanced', u'Professional'],
364                ),
365            required=False,
366            missing_value={},
367            ),
368        )
369
370@implementer(IExample)
371class Example(Container):
372    """Example instance class"""

34.2. How fields look like#

This is how these fields look like when editing content:

Default fields

Default fields#

Number fields

Number fields#

Date and time fields

Date and time fields#

Choice and multiple choice fields

Choice and multiple choice fields#

File fields

File fields#

Reference fields

Reference fields#

Other fields including the dict field

Other fields including the dict field#

34.3. 3rd party fields#

34.4. Datagrid Field#

The Datagridfield allows you to enter multiple values at once as rows in a table. Each row is a sub form defined in a separate schema.

Here is an example:

 1# -*- coding: utf-8 -*-
 2from collective.z3cform.datagridfield import DataGridFieldFactory
 3from collective.z3cform.datagridfield import DictRow
 4from plone.app.z3cform.widget import SelectFieldWidget
 5from plone.autoform import directives
 6from plone.supermodel import model
 7from zope import schema
 8from zope.interface import Interface
 9
10
11class IMyRowSchema(Interface):
12
13    choice_field = schema.Choice(
14        title=u'Choice Field',
15        vocabulary='plone.app.vocabularies.PortalTypes',
16        required=False,
17        )
18    directives.widget('objective', SelectFieldWidget)
19
20    textline_field = schema.TextLine(
21        title=u'Textline field',
22        required=False,
23        )
24
25    bool_field = schema.Bool(
26        title=u'Boolean field',
27        required=False,
28    )
29
30
31class IExampleWithDatagrid(model.Schema):
32
33    title = schema.TextLine(title=u'Title', required=True)
34
35    datagrid_field = schema.List(
36        title=u'Datagrid field',
37        value_type=DictRow(title=u'Table', schema=IMyRowSchema),
38        default=[],
39        required=False,
40    )
41    directives.widget('datagrid_field', DataGridFieldFactory)

The edit-form looks like this:

../_images/dexterity_reference_datagridfield_edit.png

The output looks like this:

../_images/dexterity_reference_datagridfield_view.png

34.5. Widgets#

Todo

Document all available widgets

34.6. Directives#

Directives can be placed anywhere in the class body (annotations are made directly on the class). By convention they are kept next to the fields they apply to.

For example, here is a schema that omits a field:

from plone.autoform import directives
from plone.supermodel import model
from zope import schema


class ISampleSchema(model.Schema):

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

    directives.omitted('additionalInfo')
    additionalInfo = schema.Bytes()

You can also handle multiple fields with one directive:

directives.omitted('field_1', 'field_2')

With the directive "mode" you can set fields to 'input', 'display' or 'hidden'.

directives.mode(additionalInfo='hidden')

You can apply directives to certain forms only. Here we drop a field from the add-form, it will still show up in the edit-form.

from z3c.form.interfaces import IAddForm

class ITask(model.Schema):

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

    directives.omitted(IAddForm, 'done')
    done = schema.Bool(
        title=_(u'Done'),
        required=False,
    )

The same works for custom forms.

With the directive widget() you can not only change the widget used for a field. With pattern_options you can pass additional parameters to the widget. Here, we configure the datetime widget powered by the JavaScript library pickadate by adding options that are used by it. Plone passes the options to the library.

class IMeeting(model.Schema):

    meeting_date = schema.Datetime(
        title=_(default=u'Date and Time'),
        required=False,
    )
    directives.widget(
        'meeting_date',
        DatetimeFieldWidget,
        pattern_options={
            'time': {'interval': 60, 'min': [7, 0], 'max': [19, 0]}},
    )

34.6.1. Validation and default values#

In the following example we add a validator and a default value.

from zope.interface import Invalid
import datetime


def future_date(value):
    if value and not value.date() >= datetime.date.today():
        raise Invalid(_(u"Meeting date can not be before today."))
    return True

def meeting_date_default_value():
    return datetime.datetime.today() + datetime.timedelta(7)


class IMeeting(model.Schema):

    meeting_date = schema.Datetime(
        title=_(default=u'Date and Time'),
        required=False,
        constraint=future_date,
        defaultFactory=meeting_date_default_value,
    )

Validators and defaults can be also be made aware of the context (i.e. to check against the values of other fields).

For context aware defaults you need to use a IContextAwareDefaultFactory. It will be passed the container for which the add form is being displayed:

from zope.interface import provider
from zope.schema.interfaces import IContextAwareDefaultFactory

@provider(IContextAwareDefaultFactory)
def get_container_id(context):
    return context.id.upper()

class IMySchema(model.Schema):

    parent_id = schema.TextLine(
        title=_(u'Parent ID'),
        required=False,
        defaultFactory=get_container_id,
    )

For context-aware validators you need to use invariant():

from zope.interface import Invalid
from zope.interface import invariant
from zope.schema.interfaces import IContextAwareDefaultFactory


class IMyEvent(model.Schema):

    start = schema.Datetime(
        title=_(u'Start date'),
        required=False)

    end = schema.Datetime(
            title=_(u"End date"),
            required=False)

    @invariant
    def validate_start_end(data):
        if data.start is not None and data.end is not None:
            if data.start > data.end:
                raise Invalid(_('Start must be before the end.'))

See also

To learn more about directives, validators and default values, refer to the following: