[Checkins] SVN: z3c.form/branches/sagblmi-nestedgroup/ Add nested group support

Laurent Mignon Laurent.Mignon at softwareag.com
Thu Feb 26 12:05:42 EST 2009


Log message for revision 97323:
  Add nested group support

Changed:
  U   z3c.form/branches/sagblmi-nestedgroup/CHANGES.txt
  U   z3c.form/branches/sagblmi-nestedgroup/src/z3c/form/group.py
  U   z3c.form/branches/sagblmi-nestedgroup/src/z3c/form/group.txt

-=-
Modified: z3c.form/branches/sagblmi-nestedgroup/CHANGES.txt
===================================================================
--- z3c.form/branches/sagblmi-nestedgroup/CHANGES.txt	2009-02-26 17:05:29 UTC (rev 97322)
+++ z3c.form/branches/sagblmi-nestedgroup/CHANGES.txt	2009-02-26 17:05:41 UTC (rev 97323)
@@ -4,6 +4,7 @@
 
 Version 2.0.0 (unreleased)
 --------------------------
+- Feature: Added Nested group support. 
 
 - Feature: Added labelRequired and requiredInfo form attributes. This is
   useful for conditional rendering a required info legend in form templates.

Modified: z3c.form/branches/sagblmi-nestedgroup/src/z3c/form/group.py
===================================================================
--- z3c.form/branches/sagblmi-nestedgroup/src/z3c/form/group.py	2009-02-26 17:05:29 UTC (rev 97322)
+++ z3c.form/branches/sagblmi-nestedgroup/src/z3c/form/group.py	2009-02-26 17:05:41 UTC (rev 97323)
@@ -21,9 +21,12 @@
 from z3c.form import form, interfaces
 from zope.interface import implements
 
+
 class Group(form.BaseForm):
     implements(interfaces.IGroup)
 
+    groups = ()
+
     def __init__(self, context, request, parentForm):
         self.context = context
         self.request = request
@@ -39,8 +42,46 @@
             setattr(self.widgets, attrName, value)
         self.widgets.update()
 
+    def update(self):
+        '''See interfaces.IForm'''
+        self.updateWidgets()
+        groups = []
+        for groupClass in self.groups:
+            # only instantiate the groupClass if it hasn't already
+            # been instantiated
+            if interfaces.IGroup.providedBy(groupClass):
+                group = groupClass
+            else:
+                group = groupClass(self.context, self.request, self)
+            group.update()
+            groups.append(group)
+        self.groups = tuple(groups)
+    
+    def extractData(self):
+        '''See interfaces.IForm'''
+        data, errors = super(Group, self).extractData()
+        for group in self.groups:
+            groupData, groupErrors = group.extractData()
+            data.update(groupData)
+            if groupErrors:
+                if errors:
+                    errors += groupErrors
+                else:
+                    errors = groupErrors
+        return data, errors
 
+    def applyChanges(self, data):
+        '''See interfaces.IEditForm'''
+        descriptions = []
+        content = self.getContent()
+        changed = form.applyChanges(self, content, data)
+        for group in self.groups:
+            groupChanged = group.applyChanges(data)
+            for interface, names in groupChanged.items():
+                changed[interface] = changed.get(interface, []) + names
+        return changed
 
+
 class GroupForm(object):
     """A mix-in class for add and edit forms to support groups."""
 
@@ -65,8 +106,7 @@
         content = self.getContent()
         changed = form.applyChanges(self, content, data)
         for group in self.groups:
-            groupContent = group.getContent()
-            groupChanged = form.applyChanges(group, groupContent, data)
+            groupChanged = group.applyChanges(data)
             for interface, names in groupChanged.items():
                 changed[interface] = changed.get(interface, []) + names
         if changed:
@@ -75,7 +115,8 @@
                     zope.lifecycleevent.Attributes(interface, *names))
             # Send out a detailed object-modified event
             zope.event.notify(
-                zope.lifecycleevent.ObjectModifiedEvent(content, *descriptions))
+                zope.lifecycleevent.ObjectModifiedEvent(content, 
+                    *descriptions))
 
         return changed
 

Modified: z3c.form/branches/sagblmi-nestedgroup/src/z3c/form/group.txt
===================================================================
--- z3c.form/branches/sagblmi-nestedgroup/src/z3c/form/group.txt	2009-02-26 17:05:29 UTC (rev 97322)
+++ z3c.form/branches/sagblmi-nestedgroup/src/z3c/form/group.txt	2009-02-26 17:05:41 UTC (rev 97323)
@@ -643,4 +643,111 @@
   >>> reg.year
   u'2005'
 
+
+Nested Groups
+-----------------
+
+The group can contains groups. 
+Let's adapt the previous RegistrationEditForm
+
+  >>> class OwnerGroup(group.Group):
+  ...     label = u'Owner'
+  ...     fields = field.Fields(IVehicleOwner, prefix='owner')
+  ...
+  ...     def getContent(self):
+  ...         return self.context.owner
+
+  >>> class VehicleRegistrationGroup(group.Group):
+  ...     label = u'Registration'
+  ...     fields = field.Fields(IVehicleRegistration).omit(
+  ...         'owner')
+  ...     groups = (OwnerGroup,)
+
+  >>> class RegistrationEditForm(group.GroupForm, form.EditForm):
+  ...     groups = (VehicleRegistrationGroup,)
+  ...
+  ...     template = viewpagetemplatefile.ViewPageTemplateFile(
+  ...         'simple_groupedit.pt', os.path.dirname(tests.__file__))
+
+
+  >>> reg = VehicleRegistration(
+  ...               license=u'MA 40387',
+  ...               address=u'10 Main St, Maynard, MA',
+  ...               model=u'BMW',
+  ...               make=u'325',
+  ...               year=u'2005',
+  ...               owner=VehicleOwner(firstName=u'Stephan',
+  ...                                  lastName=u'Richter'))
+  >>> request = testing.TestRequest()
+
+  >>> edit = RegistrationEditForm(reg, request)
+  >>> edit.update()
+
+Now let's try and edit the owner.  For example, suppose that Stephan
+Richter gave his BMW to Paul Carduner because he is such a nice guy.
+
+  >>> request = testing.TestRequest(form={
+  ...     'form.widgets.owner.firstName': u'Paul',
+  ...     'form.widgets.owner.lastName': u'Carduner',
+  ...     'form.widgets.license': u'MA 4038765',
+  ...     'form.widgets.address': u'Berkeley',
+  ...     'form.widgets.model': u'BMW',
+  ...     'form.widgets.make': u'325',
+  ...     'form.widgets.year': u'2005',
+  ...     'form.buttons.apply': u'Apply'
+  ...     })
+  >>> edit = RegistrationEditForm(reg, request)
+  >>> edit.update()
+
+We'll see if everything worked on the form side.
+
+  >>> print testing.render(edit, './/xmlns:i')
+  <i>Data successfully updated.</i>
+  
+Now the owner object should have updated fields.
+
+  >>> reg.owner.firstName
+  u'Paul'
+  >>> reg.owner.lastName
+  u'Carduner'
+  >>> reg.license
+  u'MA 4038765'
+  >>> reg.address
+  u'Berkeley'
+  >>> reg.model
+  u'BMW'
+  >>> reg.make
+  u'325'
+  >>> reg.year
+  u'2005'
+
+So what happens, if errors happen inside a nested group?
+
+  >>> request = testing.TestRequest(form={
+  ...     'form.widgets.owner.firstName': u'Paul',
+  ...     'form.widgets.license': u'MA 4038765',
+  ...     'form.widgets.model': u'BMW',
+  ...     'form.widgets.make': u'325',
+  ...     'form.widgets.year': u'2005',
+  ...     'form.buttons.apply': u'Apply'
+  ...     })
+
+  >>> edit = RegistrationEditForm(reg, request)
+  >>> edit.update()
+  >>> data, errors = edit.extractData()
+  >>> " ".join(["%s %s"%(error.widget.label, error.render()) for error in errors])
+  u'Address \n  <div class="error">Required input is missing.</div>\n\n Last Name \n  <div class="error">Required input is missing.</div>\n\n'
+
+  >>> print testing.render(edit, './/xmlns:i')
+  <i >There were some errors.</i>
+
+  >>> print testing.render(edit, './/xmlns:fieldset[1]/xmlns:ul')
+  <ul >
+     <li>
+       Address:
+       <div class="error">Required input is missing.</div>
+     </li>
+  </ul>
+
+
 And that's it!



More information about the Checkins mailing list