{ "info": { "author": "Martijn Faassen", "author_email": "faassen@startifact.com", "bugtrack_url": null, "classifiers": [], "description": "*******************\nz3c.relationfieldui \n*******************\n\nThis package implements a ``zope.formlib`` compatible widget for\nrelations as defined by `z3c.relationfield`_.\n\n.. _`z3c.relationfield`: http://pypi.python.org/pypi/z3c.relationfield\n\nThis package does not provide a ``z3c.form`` widget for\n``z3c.relationfield``, but it is hoped that will eventually be\ndeveloped as well (in another package).\n\nSetup\n=====\n\nIn order to demonstrate our widget, we need to first set up a relation\nfield (for the details of this see z3c.relationfield's\ndocumentation)::\n\n >>> from z3c.relationfield import Relation\n >>> from zope.interface import Interface\n >>> class IItem(Interface):\n ... rel = Relation(title=u\"Relation\")\n >>> from z3c.relationfield.interfaces import IHasRelations\n >>> from persistent import Persistent\n >>> from zope.interface import implements\n >>> class Item(Persistent):\n ... implements(IItem, IHasRelations)\n ... def __init__(self):\n ... self.rel = None\n >>> from zope.app.component.site import SiteManagerContainer\n >>> from zope.app.container.btree import BTreeContainer\n >>> class TestApp(SiteManagerContainer, BTreeContainer):\n ... pass\n\nSet up the application with the right utilities::\n\n >>> root = getRootFolder()['root'] = TestApp()\n >>> from zope.app.component.site import LocalSiteManager\n >>> root.setSiteManager(LocalSiteManager(root))\n >>> from zope.app.component.hooks import setSite\n >>> setSite(root)\n >>> from zope.app.intid import IntIds\n >>> from zope.app.intid.interfaces import IIntIds\n >>> root['intids'] = intids = IntIds() \n >>> sm = root.getSiteManager()\n >>> sm.registerUtility(intids, provided=IIntIds)\n >>> from z3c.relationfield import RelationCatalog\n >>> from zc.relation.interfaces import ICatalog\n >>> root['catalog'] = catalog = RelationCatalog()\n >>> sm.registerUtility(catalog, provided=ICatalog)\n\nItems ``a`` and ``b`` with a relation from ``b`` to ``a``::\n\n >>> root['a'] = Item()\n >>> from z3c.relationfield import RelationValue\n >>> b = Item()\n >>> from zope import component\n >>> from zope.app.intid.interfaces import IIntIds\n >>> intids = component.getUtility(IIntIds)\n >>> a_id = intids.getId(root['a'])\n >>> b.rel = RelationValue(a_id)\n >>> root['b'] = b\n\nWe also need to set up a utility that knows how to generate an object\npath for a given object, and back::\n\n >>> import grokcore.component as grok\n >>> from z3c.objpath.interfaces import IObjectPath\n >>> class ObjectPath(grok.GlobalUtility):\n ... grok.provides(IObjectPath)\n ... def path(self, obj):\n ... return obj.__name__\n ... def resolve(self, path):\n ... try:\n ... return root[path]\n ... except KeyError:\n ... raise ValueError(\"Cannot resolve: %s\" % path)\n >>> grok.testing.grok_component('ObjectPath', ObjectPath)\n True\n\nLet's also set up a broken relation::\n\n >>> d = root['d'] = Item()\n >>> d_id = intids.getId(root['d'])\n >>> c = Item()\n >>> c.rel = RelationValue(d_id)\n >>> root['c'] = c\n >>> del root['d']\n >>> root['c'].rel.to_object is None\n True\n >>> root['c'].rel.isBroken()\n True\n\nThe relation widget\n===================\n\nThe relation widget can be looked up for a relation field. The widget\nwill render with a button that can be used to set the\nrelation. Pressing this button will show a pop up window. The URL\nimplementing the popup window is defined on a special view that needs\nto be available on the context object (that the relation is defined\non). This view must be named \"explorerurl\". We'll provide one here::\n\n >>> from zope.interface import Interface\n >>> import grokcore.view\n >>> class ExplorerUrl(grokcore.view.View):\n ... grok.context(Interface)\n ... def render(self):\n ... return 'http://grok.zope.org'\n\nNow we can Grok the view::\n\n >>> grok.testing.grok_component('ExplorerUrl', ExplorerUrl)\n True\n\nLet's take a look at the relation widget now::\n\n >>> from zope.publisher.browser import TestRequest\n >>> from z3c.relationfieldui import RelationWidget\n >>> request = TestRequest()\n >>> field = IItem['rel']\n >>> bound = field.bind(root['b'])\n >>> widget = RelationWidget(bound, request)\n >>> widget.setRenderedValue(bound.get(root['b']))\n >>> print widget()\n \n\nLet's also try it with the broken relation::\n\n >>> bound = field.bind(root['c'])\n >>> widget = RelationWidget(bound, request)\n >>> widget.setRenderedValue(bound.get(root['c']))\n\nWhen we render the widget, the value is still correct (even though\nit's broken)::\n\n >>> print widget()\n \n\nRelation Choice\n===============\n\nLet's examine the ``RelationChoice`` field from ``z3c.relationfield``. We\nneed to provide a source of possible relations for it, and we can do this\nusing the ``RelationSourceFactory``::\n\n >>> from z3c.relationfieldui import RelationSourceFactory\n >>> class MyRelationSourceFactory(RelationSourceFactory):\n ... def getTargets(self):\n ... return [root['a'], root['b'], root['c']]\n\nIn the source, we simply return an iterable of objects that are\npossible relation targets.\n\nLet's now create an object that makes use of this source::\n\n >>> from z3c.relationfield import RelationChoice\n >>> class IItemChoice(Interface):\n ... rel = RelationChoice(title=u\"Relation\", required=False,\n ... source=MyRelationSourceFactory())\n\nWe can now take a look at the widget, using ``ChoiceInputWidget``::\n\n >>> from zope.app.form.browser import ChoiceInputWidget\n\n >>> class ItemChoice(Persistent):\n ... implements(IItemChoice, IHasRelations)\n ... def __init__(self):\n ... self.rel = None\n\n >>> root['choice_a'] = ItemChoice()\n >>> field = IItemChoice['rel']\n >>> bound = field.bind(root['choice_a'])\n >>> widget = ChoiceInputWidget(bound, request)\n\nLet's first render the widget without a particular rendered value set::\n\n >>> print widget()\n