[Product-Developers] Re: z3c.form widget traversal and validation
Laurent Mignon
laurent.mignon at softwareag.com
Fri Mar 5 07:40:32 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