Package: z3c.relationfieldui
This package implements azope.formlibcompatible widget for
relations as defined byz3c.relationfield.This package does not provide az3c.formwidget forz3c.relationfield, but it is hoped that will eventually be
developed as well (in another package).SetupIn order to demonstrate our widget, we need to first set up a relation
field (for the details of this see z3c.relationfield’s
documentation):>>> from z3c.relationfield import Relation
>>> from zope.interface import Interface
>>> class IItem(Interface):
...   rel = Relation(title=u"Relation")
>>> from z3c.relationfield.interfaces import IHasRelations
>>> from persistent import Persistent
>>> from zope.interface import implements
>>> class Item(Persistent):
...   implements(IItem, IHasRelations)
...   def __init__(self):
...     self.rel = None
>>> from zope.app.component.site import SiteManagerContainer
>>> from zope.app.container.btree import BTreeContainer
>>> class TestApp(SiteManagerContainer, BTreeContainer):
...   passSet up the application with the right utilities:>>> root = getRootFolder()['root'] = TestApp()
>>> from zope.app.component.site import LocalSiteManager
>>> root.setSiteManager(LocalSiteManager(root))
>>> from zope.app.component.hooks import setSite
>>> setSite(root)
>>> from zope.app.intid import IntIds
>>> from zope.app.intid.interfaces import IIntIds
>>> root['intids'] = intids = IntIds()
>>> sm = root.getSiteManager()
>>> sm.registerUtility(intids, provided=IIntIds)
>>> from z3c.relationfield import RelationCatalog
>>> from zc.relation.interfaces import ICatalog
>>> root['catalog'] = catalog = RelationCatalog()
>>> sm.registerUtility(catalog, provided=ICatalog)Itemsaandbwith a relation frombtoa:>>> root['a'] = Item()
>>> from z3c.relationfield import RelationValue
>>> b = Item()
>>> from zope import component
>>> from zope.app.intid.interfaces import IIntIds
>>> intids = component.getUtility(IIntIds)
>>> a_id = intids.getId(root['a'])
>>> b.rel = RelationValue(a_id)
>>> root['b'] = bWe also need to set up a utility that knows how to generate an object
path for a given object, and back:>>> import grokcore.component as grok
>>> from z3c.objpath.interfaces import IObjectPath
>>> class ObjectPath(grok.GlobalUtility):
...   grok.provides(IObjectPath)
...   def path(self, obj):
...       return obj.__name__
...   def resolve(self, path):
...       try:
...           return root[path]
...       except KeyError:
...           raise ValueError("Cannot resolve: %s" % path)
>>> grok.testing.grok_component('ObjectPath', ObjectPath)
TrueLet’s also set up a broken relation:>>> d = root['d'] = Item()
>>> d_id = intids.getId(root['d'])
>>> c = Item()
>>> c.rel = RelationValue(d_id)
>>> root['c'] = c
>>> del root['d']
>>> root['c'].rel.to_object is None
True
>>> root['c'].rel.isBroken()
TrueThe relation widgetThe relation widget can be looked up for a relation field. The widget
will render with a button that can be used to set the
relation. Pressing this button will show a pop up window. The URL
implementing the popup window is defined on a special view that needs
to be available on the context object (that the relation is defined
on). This view must be named “explorerurl”. We’ll provide one here:>>> from zope.interface import Interface
>>> import grokcore.view
>>> class ExplorerUrl(grokcore.view.View):
...   grok.context(Interface)
...   def render(self):
...      return 'http://grok.zope.org'Now we can Grok the view:>>> grok.testing.grok_component('ExplorerUrl', ExplorerUrl)
TrueLet’s take a look at the relation widget now:>>> from zope.publisher.browser import TestRequest
>>> from z3c.relationfieldui import RelationWidget
>>> request = TestRequest()
>>> field = IItem['rel']
>>> bound = field.bind(root['b'])
>>> widget = RelationWidget(bound, request)
>>> widget.setRenderedValue(bound.get(root['b']))
>>> print widget()
<input class="textType" id="field.rel" name="field.rel" size="20" type="text" value="a"  /><input class="buttonType" onclick="Z3C.relation.popup(this.previousSibling, 'http://grok.zope.org?from_attribute=rel&amp;from_path=b')" type="button" value="get relation" />Let’s also try it with the broken relation:>>> bound = field.bind(root['c'])
>>> widget = RelationWidget(bound, request)
>>> widget.setRenderedValue(bound.get(root['c']))When we render the widget, the value is still correct (even though
it’s broken):>>> print widget()
<input class="textType" id="field.rel" name="field.rel" size="20" type="text" value="d"  /><input class="buttonType" onclick="Z3C.relation.popup(this.previousSibling, 'http://grok.zope.org?from_attribute=rel&amp;from_path=c')" type="button" value="get relation" />Relation ChoiceLet’s examine theRelationChoicefield fromz3c.relationfield. We
need to provide a source of possible relations for it, and we can do this
using theRelationSourceFactory:>>> from z3c.relationfieldui import RelationSourceFactory
>>> class MyRelationSourceFactory(RelationSourceFactory):
...    def getTargets(self):
...        return [root['a'], root['b'], root['c']]In the source, we simply return an iterable of objects that are
possible relation targets.Let’s now create an object that makes use of this source:>>> from z3c.relationfield import RelationChoice
>>> class IItemChoice(Interface):
...   rel = RelationChoice(title=u"Relation", required=False,
...                        source=MyRelationSourceFactory())We can now take a look at the widget, usingChoiceInputWidget:>>> from zope.app.form.browser import ChoiceInputWidget

>>> class ItemChoice(Persistent):
...   implements(IItemChoice, IHasRelations)
...   def __init__(self):
...     self.rel = None

>>> root['choice_a'] = ItemChoice()
>>> field = IItemChoice['rel']
>>> bound = field.bind(root['choice_a'])
>>> widget = ChoiceInputWidget(bound, request)Let’s first render the widget without a particular rendered value set:>>> print widget()
<div>
<div class="value">
<select id="field.rel" name="field.rel" size="1" >
<option selected="selected" value="">(no value)</option>
<option value="a">a</option>
<option value="b">b</option>
<option value="c">c</option>
</select>
</div>
<input name="field.rel-empty-marker" type="hidden" value="1" />
</div>Let’s try it again with a value set as a relation toa:>>> choice_b = ItemChoice()
>>> choice_b.rel = RelationValue(a_id)
>>> root['choice_b'] = choice_b
>>> bound = field.bind(root['choice_b'])
>>> widget = ChoiceInputWidget(bound, request)
>>> widget.setRenderedValue(bound.get(root['b']))When we look at the widget we see that this relation is indeed selected:>>> print widget()
<div>
<div class="value">
<select id="field.rel" name="field.rel" size="1" >
<option value="">(no value)</option>
<option selected="selected" value="a">a</option>
<option value="b">b</option>
<option value="c">c</option>
</select>
</div>
<input name="field.rel-empty-marker" type="hidden" value="1" />
</div>Relation display widgetThe display widget for relation will render a URL to the object it relates
to. What this URL will be exactly can be controlled by defining a view
on the object called “relationurl”. Without such a view, the display
widget will link directly to the object:>>> from z3c.relationfieldui import RelationDisplayWidget
>>> bound = field.bind(root['b'])
>>> widget = RelationDisplayWidget(bound, request)
>>> widget.setRenderedValue(bound.get(root['b']))The widget will point to the plain URL ofrel’sto_object:>>> print widget()
<a href="http://127.0.0.1/root/a">a</a>Now we register a specialrelationurlview:>>> class RelationUrl(grokcore.view.View):
...   grok.context(Interface)
...   def render(self):
...      return self.url('edit')
>>> grok.testing.grok_component('RelationUrl', RelationUrl)
TrueWe should now see a link postfixed with/edit:>>> print widget()
<a href="http://127.0.0.1/root/a/edit">a</a>When the relation is broken, it will still display, but as broken:>>> bound = field.bind(root['c'])
>>> widget = RelationDisplayWidget(bound, request)
>>> widget.setRenderedValue(bound.get(root['c']))
>>> print widget()
Broken relation to: dCHANGES0.5 (2009-02-10)Add support forRelationChoicefield. To create a relation field that
uses a drop-down list to select the relation target, implement aRelationSourceFactory(implement thegetTargetsmethod), and
pass it as a source toRelationChoice.0.4 (2009-01-20)Use improvedz3c.relationfieldto better handle broken
relations.  Broken relations are now accepted by the UI but will be
stored as broken.0.3 (2009-01-16)Pass alongfrom_attributeandfrom_pathURL parameters to
explorer_url.0.2 (2009-01-08)Update the value of the input field using.valueinstead of
usingsetAttribute('value',...). The latter did not update
dynamically updated input fields, and the former does.z3c.relationfielddoes not useIRelationInfoanymore and
instead exposescreate_relation. Use this instead.0.1.1 (2008-12-10)Small internet Explorer compatibility tweaks.0.1 (2008-12-05)Initial public release.Download