[Product-Developers] Re: z3c.form widget traversal and validation

Laurent Mignon laurent.mignon at softwareag.com
Fri Mar 5 08:20:29 UTC 2010


Martin Aspeli wrote:
 > Hi,
 >
 > On 5 March 2010 08:17, David Glick 
<davidglick at groundwire.org> wrote:
 >> I have a z3c.form form that overrides its getContent method based on a
 >> property of the current authenticated member.  That is, the data being
 >> edited by the form depends on which user is logged in.
 >
 > Okay.
 >
 >> This form also has a NamedImage field (from plone.namedfile), which
 >> displays a preview of the current image by traversing to ++widget++logo
 >> on the form (logo is the name of the field).
 >
 > Right.
 >
 >> But this doesn't work in this case, because in order to traverse to a
 >> widget, the code that handles this traversal (in
 >> plone.z3cform.traversal) must call the form's update method, which in
 >> turn calls updateWidgets.  But update also relies on being able to get
 >> the form's data, so it calls getContent, which fails because there is no
 >> authenticated member yet, since authentication happens after traversal.
 >
 > Ouch.
 >
 >> Any ideas about how I can get out of this pickle?
 >
 > Not really. You have to do update(), otherwise you don't have enough
 > information on the widget. In a lot of cases, the fields/widgets
 > aren't even fully konwn until update() is done.
 >
 > Could you replace your getContent() return value with some kind of
 > proxy that lazily looks up the user?
 >
 > Martin

I've the same kind of issue in my application. The 'workaround' used is
to specifically mark the request during traversal request and play with
security iin the update method only if  the request is not marked as
used into the traversal conext:

My override of the traverse method looks like


def traverse(self, name, ignored):
     """Allow traversal to widgets via the ++widget++ namespace. Thecontext
     is the from layout wrapper.

     This version support nested group
     """
     # Mark the request as used in the widget traveral process
     # It may be usefull for the form, to know that it's used to alonly
     # retrive specific widget attribute
     alsoProvides(self.context.request, IWidgetTraversalRequest)

     ....



and in the update method....

def update(self):
     if not IWidgetTraversalRequest.providedBy(self.request):
     if checkPermission(ManageMatters, hooks.getSite()):
             ...


I've also fixed a issue with the original traverse method related to the
  support of nested group... (sorry I forgot to put a ticket with the
path  into the trac)

The full code of my traverse method looks like:

def traverse(self, name, ignored):
     """Allow traversal to widgets via the ++widget++ namespace. The context
     is the from layout wrapper.

     This version support nested group
     """
     # Mark the request as used in the widget traveral process
     # It may be usefull for the form, to know that it's used to alonly
     # retrive specific widget attribute
     alsoProvides(self.context.request, IWidgetTraversalRequest)

     form = self.context.form_instance
     z2.switch_on(self.context, request_layer=self.context.request_layer)

     form.update()
     # Find the widget
     if name in form.widgets:
         return form.widgets.get(name)

     # it may be in a group
     def traverseGroup(form, name):
         for group in getattr(form, 'groups', []) or []:
             if name in group.widgets:
                 return group.widgets.get(name)
             #recursive call
             widget = traverseGroup(group, name)
             if widget is not None:
                 # Make the parent of the widget the traversal parent.
                 # This is required for security to work in Zope 2.12
                 widget.__parent__ = aq_inner(self.context)
                 return widget
         return None
     return traverseGroup(form, name)


Laurent






More information about the Product-Developers mailing list