[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