[Checkins] SVN: z3c.form/trunk/src/z3c/form/f The readonly flag
within a field was never honored. When a field is
Stephan Richter
srichter at cosmos.phy.tufts.edu
Wed Jun 13 00:48:55 EDT 2007
Log message for revision 76652:
The readonly flag within a field was never honored. When a field is
readonly now, it is displayed in "display" mode. This can be overridden
by the widget manager's "ignoreReadonly" flag.
Changed:
U z3c.form/trunk/src/z3c/form/field.py
U z3c.form/trunk/src/z3c/form/field.txt
U z3c.form/trunk/src/z3c/form/form.py
U z3c.form/trunk/src/z3c/form/form.txt
-=-
Modified: z3c.form/trunk/src/z3c/form/field.py
===================================================================
--- z3c.form/trunk/src/z3c/form/field.py 2007-06-13 00:18:16 UTC (rev 76651)
+++ z3c.form/trunk/src/z3c/form/field.py 2007-06-13 04:48:54 UTC (rev 76652)
@@ -177,6 +177,7 @@
errors = ()
ignoreContext = False
ignoreRequest = False
+ ignoreReadonly = False
def __init__(self, form, request, content):
super(FieldWidgets, self).__init__()
@@ -218,7 +219,10 @@
# Step 1: Determine the mode of the widget.
mode = field.mode
if mode is None:
- mode = self.mode
+ if field.field.readonly and not self.ignoreReadonly:
+ mode = interfaces.DISPLAY_MODE
+ else:
+ mode = self.mode
# Step 2: Get the widget for the given field.
factory = field.widgetFactory.get(mode)
if factory is not None:
@@ -254,6 +258,8 @@
data = {}
self.errors = ()
for name, widget in self.items():
+ if widget.mode == interfaces.DISPLAY_MODE:
+ continue
raw = widget.extract()
value = widget.field.missing_value
try:
Modified: z3c.form/trunk/src/z3c/form/field.txt
===================================================================
--- z3c.form/trunk/src/z3c/form/field.txt 2007-06-13 00:18:16 UTC (rev 76651)
+++ z3c.form/trunk/src/z3c/form/field.txt 2007-06-13 04:48:54 UTC (rev 76652)
@@ -316,6 +316,12 @@
... """The last name is too short."""
>>> class IPerson(zope.interface.Interface):
+ ... id = zope.schema.TextLine(
+ ... title=u'ID',
+ ... description=u"The person's ID.",
+ ... readonly=True,
+ ... required=True)
+ ...
... lastName = zope.schema.TextLine(
... title=u'Last Name',
... description=u"The person's last name.",
@@ -388,7 +394,7 @@
in a particular order:
>>> manager.keys()
- ['lastName', 'firstName']
+ ['id', 'lastName', 'firstName']
Let's make sure that all enumerable mapping functions work correctly:
@@ -412,18 +418,20 @@
False
>>> [key for key in manager]
- ['lastName', 'firstName']
+ ['id', 'lastName', 'firstName']
>>> manager.values()
- [<Widget 'form.widgets.lastName'>,
+ [<Widget 'form.widgets.id'>,
+ <Widget 'form.widgets.lastName'>,
<Widget 'form.widgets.firstName'>]
>>> manager.items()
- [('lastName', <Widget 'form.widgets.lastName'>),
+ [('id', <Widget 'form.widgets.id'>),
+ ('lastName', <Widget 'form.widgets.lastName'>),
('firstName', <Widget 'form.widgets.firstName'>)]
>>> len(manager)
- 2
+ 3
When a widget is added to the widget manager, it is located:
@@ -441,7 +449,7 @@
>>> lname.context is context
True
-All widgets will also assume the mode of the manager:
+By default, all widgets will also assume the mode of the manager:
>>> manager['lastName'].mode
'input'
@@ -452,10 +460,26 @@
>>> manager['lastName'].mode
'display'
-The exception is when some fields specifically desire a different mode. In
-this case, the last name will inherit the mode from the widget manager, while
-the first name will want to use a display wdget:
+The exception is when some fields specifically desire a different mode. In the
+first case, all "readonly" fields will be shown in display mode:
+ >>> manager.mode = interfaces.INPUT_MODE
+ >>> manager.update()
+
+ >>> manager['id'].mode
+ 'display'
+
+An exception is made when the flag, "ignoreReadonly" is set:
+
+ >>> manager.ignoreReadonly = True
+ >>> manager.update()
+
+ >>> manager['id'].mode
+ 'input'
+
+In the second case, the last name will inherit the mode from the widget
+manager, while the first name will want to use a display wdget:
+
>>> addPerson.fields = field.Fields(IPerson).select('lastName')
>>> addPerson.fields += field.Fields(
... IPerson, mode=interfaces.DISPLAY_MODE).select('firstName')
@@ -468,7 +492,6 @@
>>> manager['firstName'].mode
'display'
-
Besides managing widgets, the widget manager also controls the process of
extracting and validating extracted data. Let's start with the validation
first, which only validates the data as a whole, assuming each individual
@@ -524,14 +547,17 @@
empty:
>>> request = TestRequest(form={
+ ... 'form.widgets.id': u'srichter',
... 'form.widgets.firstName': u'Stephan',
... 'form.widgets.lastName': u'Richter'})
>>> manager = field.FieldWidgets(addPerson, request, context)
>>> manager.ignoreContext = True
>>> manager.update()
- >>> manager.extract()
- ({'lastName': u'Richter', 'firstName': u'Stephan'}, ())
+ >>> from zope.testing.doctestunit import pprint
+ >>> pprint(manager.extract())
+ ({'firstName': u'Stephan', 'lastName': u'Richter'}, ())
+
Since all errors are immediately converted to error view snippets, we have to
provide the adapter from a validation error to an error view snippet first:
@@ -542,7 +568,7 @@
name:
>>> request = TestRequest(form={
- ... 'form.widgets.firstName': u'Stephan'})
+ ... 'form.widgets.firstName': u'Stephan', 'form.widgets.id': u'srichter'})
>>> manager = field.FieldWidgets(addPerson, request, context)
>>> manager.ignoreContext = True
>>> manager.update()
@@ -552,6 +578,7 @@
Finally, let's ensure that invariant failures are also caught:
>>> request = TestRequest(form={
+ ... 'form.widgets.id': u'srichter',
... 'form.widgets.firstName': u'Stephan',
... 'form.widgets.lastName': u'Richter-Richter'})
>>> manager = field.FieldWidgets(addPerson, request, context)
Modified: z3c.form/trunk/src/z3c/form/form.py
===================================================================
--- z3c.form/trunk/src/z3c/form/form.py 2007-06-13 00:18:16 UTC (rev 76651)
+++ z3c.form/trunk/src/z3c/form/form.py 2007-06-13 04:48:54 UTC (rev 76652)
@@ -34,6 +34,10 @@
def applyChanges(form, content, data):
changed = False
for name, field in form.fields.items():
+ # If the field is not in the data, then go on to the next one
+ if name not in data:
+ continue
+ # Get the datamanager and get the original value
dm = zope.component.getMultiAdapter(
(content, field.field), interfaces.IDataManager)
oldValue = dm.get()
@@ -43,6 +47,7 @@
changed = True
return changed
+
def extends(*args, **kwargs):
frame = sys._getframe(1)
f_locals = frame.f_locals
@@ -162,6 +167,7 @@
self.widgets = zope.component.getMultiAdapter(
(self, self.request, self.getContent()), interfaces.IWidgets)
self.widgets.ignoreContext = True
+ self.widgets.ignoreReadonly = True
self.widgets.update()
def create(self, data):
Modified: z3c.form/trunk/src/z3c/form/form.txt
===================================================================
--- z3c.form/trunk/src/z3c/form/form.txt 2007-06-13 00:18:16 UTC (rev 76651)
+++ z3c.form/trunk/src/z3c/form/form.txt 2007-06-13 04:48:54 UTC (rev 76652)
@@ -22,6 +22,11 @@
>>> import zope.schema
>>> class IPerson(zope.interface.Interface):
...
+ ... id = zope.schema.TextLine(
+ ... title=u'ID',
+ ... readonly=True,
+ ... required=True)
+ ...
... name = zope.schema.TextLine(
... title=u'Name',
... required=True)
@@ -41,11 +46,13 @@
>>> from zope.schema.fieldproperty import FieldProperty
>>> class Person(object):
... zope.interface.implements(IPerson)
+ ... id = FieldProperty(IPerson['id'])
... name = FieldProperty(IPerson['name'])
... gender = FieldProperty(IPerson['gender'])
... age = FieldProperty(IPerson['age'])
...
- ... def __init__(self, name, gender=None, age=None):
+ ... def __init__(self, id, name, gender=None, age=None):
+ ... self.id = id
... self.name = name
... if gender:
... self.gender = gender
@@ -97,7 +104,7 @@
... return Person(**data)
...
... def add(self, object):
- ... self.context[object.name] = object
+ ... self.context[object.id] = object
...
... def nextURL(self):
... return 'index.html'
@@ -145,7 +152,7 @@
The widget manager will have three widgets, one for each field:
>>> addForm.widgets.keys()
- ['name', 'gender', 'age']
+ ['id', 'name', 'gender', 'age']
When the widget manager updates itself, several sub-tasks are processed. The
manager goes through each field, trying to create a fully representative
@@ -218,7 +225,7 @@
* The permission to the content's data value
* The manual ``mode`` flag in the field
-* The ``read_only`` flag in the schema field
+* The ``readonly`` flag in the schema field
Widget Attribute Values
@@ -285,6 +292,11 @@
<body>
<form action=".">
<div class="row">
+ <label for="form-widgets-id">ID</label>
+ <input type="text" id="form-widgets-id"
+ name="form.widgets.id" class="textWidget" value="" />
+ </div>
+ <div class="row">
<label for="form-widgets-name">Name</label>
<input type="text" id="form-widgets-name" name="form.widgets.name"
class="textWidget" value="" />
@@ -322,6 +334,7 @@
the form with the "Add" button, the person should be added to the root folder:
>>> request = TestRequest(form={
+ ... 'form.widgets.id': u'srichter',
... 'form.widgets.name': u'Stephan Richter',
... 'form.widgets.gender': ['male'],
... 'form.widgets.age': u'20',
@@ -332,8 +345,10 @@
>>> addForm.update()
>>> sorted(root)
- [u'Stephan Richter']
- >>> stephan = root[u'Stephan Richter']
+ [u'srichter']
+ >>> stephan = root[u'srichter']
+ >>> stephan.id
+ u'srichter'
>>> stephan.name
u'Stephan Richter'
>>> stephan.gender
@@ -350,6 +365,7 @@
pointing out the error.
>>> request = TestRequest(form={
+ ... 'form.widgets.id': u'srichter',
... 'form.widgets.gender': ['male'],
... 'form.widgets.age': u'23',
... 'form.buttons.add': u'Add'}
@@ -381,6 +397,11 @@
</ul>
<form action=".">
<div class="row">
+ <label for="form-widgets-id">ID</label>
+ <input type="text" id="form-widgets-id"
+ name="form.widgets.id" class="textWidget" value="srichter" />
+ </div>
+ <div class="row">
<b><div class="error">Required input is missing.</div>
</b><label for="form-widgets-name">Name</label>
<input type="text" id="form-widgets-name" name="form.widgets.name"
@@ -417,6 +438,7 @@
Let's now also provide a negative age, which is not possible either:
>>> request = TestRequest(form={
+ ... 'form.widgets.id': u'srichter',
... 'form.widgets.gender': ['male'],
... 'form.widgets.age': u'-5',
... 'form.buttons.add': u'Add'}
@@ -647,7 +669,7 @@
We can use the created person from the successful addition above.
- >>> editForm = PersonEditForm(root[u'Stephan Richter'], TestRequest())
+ >>> editForm = PersonEditForm(root[u'srichter'], TestRequest())
After adding a template, we can look at the form:
@@ -658,6 +680,10 @@
<body>
<form action=".">
<div class="row">
+ <label for="form-widgets-id">ID</label>
+ srichter
+ </div>
+ <div class="row">
<label for="form-widgets-name">Full Name</label>
<input type="text" id="form-widgets-name" name="form.widgets.name"
class="textWidget" value="Stephan Richter" />
@@ -704,7 +730,7 @@
... 'form.buttons.apply': u'Apply'}
... )
- >>> editForm = PersonEditForm(root[u'Stephan Richter'], request)
+ >>> editForm = PersonEditForm(root[u'srichter'], request)
>>> addTemplate(editForm)
>>> editForm.update()
>>> print editForm.render()
@@ -718,6 +744,10 @@
</ul>
<form action=".">
<div class="row">
+ <label for="form-widgets-id">ID</label>
+ srichter
+ </div>
+ <div class="row">
<label for="form-widgets-name">Full Name</label>
<input type="text" id="form-widgets-name" name="form.widgets.name"
class="textWidget" value="Claudia Richter" />
@@ -762,7 +792,7 @@
... 'form.buttons.apply': u'Apply'}
... )
- >>> editForm = PersonEditForm(root[u'Stephan Richter'], request)
+ >>> editForm = PersonEditForm(root[u'srichter'], request)
>>> addTemplate(editForm)
>>> editForm.update()
>>> print editForm.render()
@@ -771,7 +801,7 @@
<i>Data successfully updated.</i>
...
- >>> stephan = root[u'Stephan Richter']
+ >>> stephan = root[u'srichter']
>>> stephan.name
u'Claudia Richter'
>>> stephan.gender
@@ -792,7 +822,7 @@
... 'form.buttons.apply': u'Apply'}
... )
- >>> editForm = PersonEditForm(root[u'Stephan Richter'], request)
+ >>> editForm = PersonEditForm(root[u'srichter'], request)
>>> addTemplate(editForm)
>>> editForm.update()
>>> print editForm.render()
@@ -848,7 +878,7 @@
The only step the developer has to complete is to re-implement the form's
``getContent()`` method to return the dictionary:
- >>> personDict = {'name': u'Roger Ineichen'}
+ >>> personDict = {'id': u'rineichen', 'name': u'Roger Ineichen'}
>>> class PersonDictEditForm(PersonEditForm):
... def getContent(self):
... return personDict
@@ -863,6 +893,10 @@
<body>
<form action=".">
<div class="row">
+ <label for="form-widgets-id">ID</label>
+ rineichen
+ </div>
+ <div class="row">
<label for="form-widgets-name">Full Name</label>
<input type="text" id="form-widgets-name"
name="form.widgets.name" class="textWidget"
@@ -911,6 +945,7 @@
>>> pprint(personDict)
{'age': 5,
'gender': 'male',
+ 'id': u'rineichen',
'name': u'Jesse Ineichen'}
@@ -930,6 +965,9 @@
<html>
<body>
<div class="row">
+ srichter
+ </div>
+ <div class="row">
Claudia Richter
</div>
<div class="row">
@@ -1074,7 +1112,7 @@
We can see that the custom widget gets used in the rendered form:
- >>> myEdit = MyEditForm(root[u'Stephan Richter'], TestRequest())
+ >>> myEdit = MyEditForm(root[u'srichter'], TestRequest())
>>> addTemplate(myEdit)
>>> myEdit.update()
>>> print myEdit.render()
More information about the Checkins
mailing list