Skip to content

Commit a8c9d60

Browse files
authored
Merge pull request #1571 from plone/classic-ui-autoforms
Add `plone.autoform` documentation for classic UI
2 parents 1bf7801 + b0e2f63 commit a8c9d60

File tree

4 files changed

+289
-21
lines changed

4 files changed

+289
-21
lines changed

docs/backend/fields.md

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -136,19 +136,43 @@ See {ref}`backend-ploneschema-label` for more details.
136136

137137
(backend-fields-schema-label)=
138138

139-
## schema
139+
## Schema
140140

141+
With `plone.autoform` and `plone.supermodel` we can use directives to add information to the schema fields.
141142

142-
(backend-fields-schema-autoform-label)=
143143

144-
### `autoform` (directives) schema ordering, filtering, and permissions
144+
(backend-fields-schema-autoform-permission)=
145145

146+
### Protect a field with a permission
146147

147-
(backend-fields-supermodel-label)=
148+
By default, fields are included in the form regardless of the user's permissions.
149+
Fields can be protected using the `read_permission` and `write_permission` directives.
150+
The read permission is checked when the field is in display mode, and the write permission is checked when the field is in input mode.
151+
The permission should be given with its Zope 3-style name, such as `cmf.ManagePortal` instead of `Manage portal`.
148152

149-
## `supermodel` (XML)
153+
In this example, the `secret` field is protected by the `cmf.ManagePortal` permission as both a read and write permission.
154+
This means that in both display and input modes, the field will only be included in the form for users who have that permission:
150155

156+
```python
157+
from plone.supermodel import model
158+
from plone.autoform import directives as form
151159

152-
(backend-fields-supermodel-autoform-label)=
160+
class IMySchema(model.Schema):
161+
form.read_permission(secret="cmf.ManagePortal")
162+
form.write_permission(secret="cmf.ManagePortal")
163+
secret = schema.TextLine(
164+
title = "Secret",
165+
)
166+
```
167+
168+
In supermodel XML, the directives are `security:read-permission` and
169+
`security:write-permission`:
153170

154-
### `autoform` (directives) supermodel ordering, filtering, and permissions
171+
```xml
172+
<field type="zope.schema.TextLine"
173+
name="secret"
174+
security:read-permission="cmf.ManagePortal"
175+
security:write-permission="cmf.ManagePortal">
176+
<title>Secret</title>
177+
</field>
178+
```

docs/backend/schemas.md

Lines changed: 142 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,148 @@ Note this won't have behavior fields added to it at this stage, only the fields
217217
- {doc}`reference list of fields used in Plone </backend/fields>`
218218

219219

220+
(backend-schemas-directives-label)=
221+
222+
## Schema directives
223+
224+
With `plone.autoform` and `plone.supermodel`, we can use directives to add information to the schema fields.
225+
226+
227+
### Omit fields
228+
229+
A field can be omitted entirely from all forms, or from some forms, using the `omitted` and `no_omit` directives.
230+
In this example, the `dummy` field is omitted from all forms, and the `edit_only` field is omitted from all forms except those that provide the `IEditForm` interface:
231+
232+
```{code-block} python
233+
:emphasize-lines: 7,12,13
234+
:linenos:
235+
236+
from z3c.form.interfaces import IEditForm
237+
from plone.supermodel import model
238+
from plone.autoform import directives as form
239+
240+
class IMySchema(model.Schema):
241+
242+
form.omitted("dummy")
243+
dummy = schema.Text(
244+
title="Dummy"
245+
)
246+
247+
form.omitted("edit_only")
248+
form.no_omit(IEditForm, "edit_only")
249+
edit_only = schema.TextLine(
250+
title = "Only included on edit forms",
251+
)
252+
```
253+
254+
In supermodel XML, this can be specified as:
255+
256+
```{code-block} xml
257+
:emphasize-lines: 3,9
258+
259+
<field type="zope.schema.TextLine"
260+
name="dummy"
261+
form:omitted="true">
262+
<title>Dummy</title>
263+
</field>
264+
265+
<field type="zope.schema.TextLine"
266+
name="edit-only"
267+
form:omitted="z3c.form.interfaces.IForm:true z3c.form.interfaces.IEditForm:false">
268+
<title>Only included on edit form</title>
269+
</field>
270+
```
271+
272+
`form:omitted` may be either a single boolean value, or a space-separated list of `<form_interface>:<boolean>` pairs.
273+
274+
275+
### Reorder fields
276+
277+
A field's position in the form can be influenced using the `order_before` and `order_after` directives.
278+
In this example, the `not_last` field is placed before the `summary` field, even though it is defined afterward:
279+
280+
```{code-block} python
281+
:emphasize-lines: 12
282+
:linenos:
283+
284+
from plone.supermodel import model
285+
from plone.autoform import directives as form
286+
287+
class IMySchema(model.Schema):
288+
289+
summary = schema.Text(
290+
title="Summary",
291+
description="Summary of the body",
292+
readonly=True
293+
)
294+
295+
form.order_before(not_last="summary")
296+
not_last = schema.TextLine(
297+
title="Not last",
298+
)
299+
```
300+
301+
The value passed to the directive may be either `*`, indicating before or after all fields, or the name of another field.
302+
Use `.<fieldname>` to refer to the field in the current schema or a base schema.
303+
Prefix with the schema name, such as `IDublinCore.title`, to refer to a field in another schema.
304+
Use an unprefixed name to refer to a field in either the current or default schema for the form.
305+
306+
In supermodel XML, the directives are called `form:before` and `form:after`.
307+
For example:
308+
309+
```{code-block} xml
310+
:emphasize-lines: 3
311+
312+
<field type="zope.schema.TextLine"
313+
name="not_last"
314+
form:before="*">
315+
<title>Not last</title>
316+
</field>
317+
```
318+
319+
320+
### Organizing fields into fieldsets
321+
322+
Fields can be grouped into fieldsets, which will be rendered within an HTML `<fieldset>` tag.
323+
In this example the `footer` and `dummy` fields are placed within the `extra` fieldset:
324+
325+
```{code-block} python
326+
:emphasize-lines: 6-9
327+
:linenos:
328+
329+
from plone.supermodel import model
330+
from plone.autoform import directives as form
331+
332+
class IMySchema(model.Schema):
333+
334+
model.fieldset("extra",
335+
label="Extra info",
336+
fields=["footer", "dummy"]
337+
)
338+
339+
footer = schema.Text(
340+
title="Footer text",
341+
)
342+
343+
dummy = schema.Text(
344+
title="Dummy"
345+
)
346+
```
347+
348+
In supermodel XML, fieldsets are specified by grouping fields within a `<fieldset>` tag:
349+
350+
```xml
351+
<fieldset name="extra" label="Extra info">
352+
<field name="footer" type="zope.schema.TextLine">
353+
<title>Footer text</title>
354+
</field>
355+
<field name="dummy" type="zope.schema.TextLine">
356+
<title>Dummy</title>
357+
</field>
358+
</fieldset>
359+
```
360+
361+
220362
## Advanced
221363

222364
```{note}
@@ -588,17 +730,4 @@ def fields(self):
588730
f.field = schema_field
589731
```
590732

591-
#### Don't use dict `{}` or list `[]` as a default value
592-
593-
Because of how Python object construction works, giving `[]` or `{}` as a default value will make all created field values share this same object.
594-
595-
```{seealso}
596-
[The Hitchhiker's Guide to Python, Common Gotchas](https://docs.python-guide.org/writing/gotchas)
597-
```
598-
599-
Use value adapters instead.
600-
601-
```{seealso}
602-
[`plone.directives.form` documentation of Value adapters](https://pypi.org/project/plone.directives.form/#value-adapters)
603-
```
604733

docs/backend/widgets.md

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,75 @@ The main widgets are:
6363
- DateTime Picker
6464

6565

66-
## Changing a field's widget
66+
(backend-widgets-change-a-fields-display-label)=
67+
68+
## Change a field's display mode
69+
70+
A field's widget can be displayed in several modes.
71+
72+
`input`
73+
: Allows the user to enter data into the field
74+
75+
`display`
76+
: A read-only indication of the field's value
77+
78+
`hidden`
79+
: A record of the field's value that is included only in the HTML source
80+
81+
82+
### `plone.autoform` `mode` directive
83+
84+
In the following example, the mode for the `secret` field is set to `hidden` for most forms, but `input` for forms that provide the `IEditForm` interface.
85+
86+
```{code-block} python
87+
:emphasize-lines: 6,7
88+
:linenos:
89+
90+
from plone.supermodel import model
91+
from plone.autoform import directives as form
92+
93+
class IMySchema(model.Schema):
94+
95+
form.mode(secret="hidden")
96+
form.mode(IEditForm, secret="input")
97+
secret = schema.TextLine(
98+
title="Secret",
99+
default="Secret stuff (except on edit forms)"
100+
)
101+
```
102+
103+
The corresponding supermodel XML directive is `form:mode`:
104+
105+
```{code-block} xml
106+
:emphasize-lines: 3
107+
108+
<field type="zope.schema.TextLine"
109+
name="secret"
110+
form:mode="z3c.form.interfaces.IForm:hidden z3c.form.interfaces.IEditForm:input">
111+
<title>Secret</title>
112+
<description>Secret stuff (except on edit forms)</description>
113+
</field>
114+
```
115+
116+
The mode can be specified briefly, if it should be the same for all forms:
117+
118+
```{code-block} xml
119+
:emphasize-lines: 3
120+
121+
<field type="zope.schema.TextLine"
122+
name="secret"
123+
form:mode="hidden">
124+
<title>Secret</title>
125+
<description>Secret stuff</description>
126+
</field>
127+
```
128+
129+
In other words, `form:mode` may be either a single mode, or a space-separated list of `<form_interface>:<mode>` pairs.
130+
131+
132+
(backend-widgets-change-a-fields-widget-label)=
133+
134+
## Change a field's widget
67135

68136
You can change the widget that you use for a field in several ways.
69137
This section describes these methods.

docs/classic-ui/forms.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,53 @@ schema = IMyForm
120120
If your form is not bound to an object (such as a Dexterity object), set `ignoreContext = True`.
121121

122122

123+
(classic-ui-controlling-form-presentation-label)=
124+
125+
## Controlling form presentation
126+
127+
Directives can be specified in the schema to control aspects of form presentation.
128+
129+
### Control field and widget presentation
130+
131+
See the corresponding chapters to learn how to control field and widget presentation in a form.
132+
133+
```{seealso}
134+
- {ref}`backend-fields-schema-autoform-permission`
135+
- {ref}`backend-schemas-directives-label`
136+
- {ref}`backend-widgets-change-a-fields-display-label`
137+
- {ref}`backend-widgets-change-a-fields-widget-label`
138+
```
139+
140+
141+
### Display Forms
142+
143+
Sometimes rather than rendering a form for data entry, you want to display stored values based on the same schema.
144+
This can be done using a "display form".
145+
The display form renders each field's widget in "display mode", which means that it shows the field value in read-only form rather than as a form input.
146+
147+
To use the display form, create a view that extends `WidgetsView` like this:
148+
149+
```python
150+
from plone.autoform.view import WidgetsView
151+
152+
class MyView(WidgetsView):
153+
schema = IMySchema
154+
additionalSchemata = (ISchemaOne, ISchemaTwo,)
155+
```
156+
157+
To render the form, do not override `__call__()`.
158+
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.
159+
160+
In the template, you can use the following variables:
161+
162+
- `view/w` is a dictionary of all widgets, including those from non-default fieldsets.
163+
By contrast, the `widgets` variable contains only those widgets in the default fieldset.
164+
The keys are the field names, and the values are widget instances.
165+
To render a widget (in display mode), you can do `tal:replace="structure view/w/myfield/render" />`.
166+
- `view/fieldsets` is a dictionary of all fieldsets not including the default fieldset, in other words, those widgets not placed into a fieldset.
167+
The keys are the fieldset names, and the values are the fieldset form instances, which in turn have variables, such as `widgets`, given a list of all widgets.
168+
169+
123170
(classic-ui-forms-dexterity-add-edit-forms-label)=
124171

125172
## Dexterity add and edit forms

0 commit comments

Comments
 (0)