Customizing widget lookup for IChoice

Widgets for fields implementing IChoice are looked up not only according to the field, but also according to the source used by the field.

>>> import z3c.form.testing
>>> import zope.interface
>>> import zope.component
>>> from z3c.form import interfaces
>>> from z3c.form.testing import TestRequest
>>> z3c.form.testing.setupFormDefaults()
>>> def setupWidget(field):
...     request = TestRequest()
...     widget = zope.component.getMultiAdapter((field, request),
...         interfaces.IFieldWidget)
...     widget.id = 'foo'
...     widget.name = 'bar'
...     return widget

We define a sample field and source:

>>> from zope.schema import vocabulary
>>> terms = [vocabulary.SimpleTerm(*value) for value in
...          [(True, 'yes', 'Yes'), (False, 'no', 'No')]]
>>> vocabulary = vocabulary.SimpleVocabulary(terms)
>>> field = zope.schema.Choice(default=True, vocabulary=vocabulary)

The default widget is the SelectWidget:

>>> widget = setupWidget(field)
>>> type(widget)
<class 'z3c.form.browser.select.SelectWidget'>

But now we define a marker interface and have our source provide it:

>>> from z3c.form.widget import FieldWidget
>>> class ISampleSource(zope.interface.Interface):
...     pass
>>> zope.interface.alsoProvides(vocabulary, ISampleSource)

We can then create and register a special widget for fields using sources with the ISampleSource marker:

>>> class SampleSelectWidget(z3c.form.browser.select.SelectWidget):
...     pass
>>> def SampleSelectFieldWidget(field, source, request):
...     return FieldWidget(field, SampleSelectWidget(request))
>>> zope.component.provideAdapter(
...   SampleSelectFieldWidget,
...   (zope.schema.interfaces.IChoice, ISampleSource, interfaces.IFormLayer),
...   interfaces.IFieldWidget)

If we now look up the widget for the field, we get the specialized widget:

>>> widget = setupWidget(field)
>>> type(widget)
<class 'SampleSelectWidget'>

Backwards compatibility

To maintain backwards compatibility, SelectFieldWidget() still can be called without passing a source:

>>> import z3c.form.browser.select
>>> request = TestRequest()
>>> widget = z3c.form.browser.select.SelectFieldWidget(field, request)
>>> type(widget)
<class 'z3c.form.browser.select.SelectWidget'>

Table Of Contents

Previous topic

Select Widget

Next topic

Submit Widget

This Page