Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions news/29.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix traversing to widgets nested in an object widget [ale-rt]
9 changes: 9 additions & 0 deletions src/plone/z3cform/traversal.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from plone.z3cform.interfaces import IDeferSecurityCheck
from plone.z3cform.interfaces import IFormWrapper
from z3c.form import util
from z3c.form.browser.object import ObjectWidget
from z3c.form.interfaces import IForm
from zope.component import adapter
from zope.interface import alsoProvides
Expand Down Expand Up @@ -86,6 +87,14 @@ def traverse(self, name, ignored):
parts.remove("widgets")
else:
raise TraversalError("'" + part + "' not valid index")
elif isinstance(target, ObjectWidget):
# ObjectWidget is a special case, we need to look for
# the name in the widget list
try:
name = parts.pop(0)
target = target.widgets[name]
except (IndexError, KeyError):
target = None
elif hasattr(target, "widgets"): # Either base form, or subform
# Check to see if we can find a "Behaviour.widget"
new_target = None
Expand Down
27 changes: 22 additions & 5 deletions src/plone/z3cform/traversal.txt
Original file line number Diff line number Diff line change
Expand Up @@ -211,16 +211,33 @@ We can find this object widget
>>> obj_widget
<ObjectWidget 'form.widgets.obj_field'>

And traverse through to the form within
We initialize the traverses to the form within:

>>> traverser = get_traverser(Bar(),u"test-parent-form")
>>> list_widget = traverser.traverse('obj_field.list_field', [])

The form is the traverser context:
>>> traverser.context.__class__
<class 'MyParentForm'>

We want to traverse to the list_field widget within the object field:
>>> traverser.context.update()
Updating test form
>>> list_field_widget = traverser.context.widgets["obj_field"].widgets["list_field"]
>>> list_field_widget
<MultiWidget 'form.widgets.obj_field.widgets.list_field'>

The widget as a prefix:
>>> list_field_widget.prefix
'form.widgets.obj_field.widgets.list_field'

To traverse to it we need to remove the form and widgets prefixes:
>>> list_widget = traverser.traverse('obj_field.widgets.list_field', [])
Updating test form
>>> list_widget
<MultiWidget 'form.widgets.obj_field.widgets.list_field'>

>>> traverser = get_traverser(Bar(),u"test-parent-form")
>>> age_widget = traverser.traverse('obj_field.list_field.0', [])
>>> age_widget = traverser.traverse('obj_field.widgets.list_field.0', [])
Updating test form
>>> age_widget
<TextWidget 'form.widgets.obj_field.widgets.list_field.0'>
Expand All @@ -230,10 +247,10 @@ And traverse through to the form within
Missing widgets are LocationErrors

>>> traverser = get_traverser(Bar(),u"test-parent-form")
>>> list_widget = traverser.traverse('obj_field.camel_field', [])
>>> list_widget = traverser.traverse('obj_field.widgets.camel_field', [])
Traceback (most recent call last):
File "<stdin>", line 1, in ?
zope.location.interfaces.LocationError: 'camel_field'
zope.location.interfaces.LocationError: 'widgets'

Looking for anything other than 'widgets' is also an error

Expand Down