[Checkins] SVN: z3c.relationfield/trunk/ Support for RelationList fields.
Martijn Faassen
faassen at infrae.com
Thu Dec 11 13:31:31 EST 2008
Log message for revision 93915:
Support for RelationList fields.
Changed:
U z3c.relationfield/trunk/CHANGES.txt
U z3c.relationfield/trunk/src/z3c/relationfield/README.txt
U z3c.relationfield/trunk/src/z3c/relationfield/__init__.py
U z3c.relationfield/trunk/src/z3c/relationfield/event.py
U z3c.relationfield/trunk/src/z3c/relationfield/interfaces.py
U z3c.relationfield/trunk/src/z3c/relationfield/schema.py
-=-
Modified: z3c.relationfield/trunk/CHANGES.txt
===================================================================
--- z3c.relationfield/trunk/CHANGES.txt 2008-12-11 18:22:35 UTC (rev 93914)
+++ z3c.relationfield/trunk/CHANGES.txt 2008-12-11 18:31:31 UTC (rev 93915)
@@ -4,7 +4,9 @@
0.2 (unreleased)
================
-* ...
+* Added support for ``RelationList`` fields. This allows one to
+ maintain a list of ``RelationValue`` objects that will be cataloged
+ like the regular ``Relation`` fields.
0.1 (2008-12-05)
================
Modified: z3c.relationfield/trunk/src/z3c/relationfield/README.txt
===================================================================
--- z3c.relationfield/trunk/src/z3c/relationfield/README.txt 2008-12-11 18:22:35 UTC (rev 93914)
+++ z3c.relationfield/trunk/src/z3c/relationfield/README.txt 2008-12-11 18:31:31 UTC (rev 93915)
@@ -382,6 +382,55 @@
>>> l[0].from_path
u'b'
+RelationList
+============
+
+Let's now experiment with the ``RelationList`` field which can be used
+to maintain a list of relations::
+
+ >>> from z3c.relationfield import RelationList
+ >>> class IMultiItem(Interface):
+ ... rel = RelationList(title=u"Relation")
+
+We also define a class ``MultiItem`` that implements both
+``IMultiItem`` and the special
+``z3c.relationfield.interfaces.IHasRelations`` interface::
+
+ >>> class MultiItem(Persistent):
+ ... implements(IMultiItem, IHasRelations)
+ ... def __init__(self):
+ ... self.rel = None
+
+We set up a few object we can then create relations between::
+
+ >>> root['multi1'] = MultiItem()
+ >>> root['multi2'] = MultiItem()
+ >>> root['multi3'] = MultiItem()
+
+Let's create a relation from ``multi1`` to both ``multi2`` and
+``multi3``::
+
+ >>> multi1_id = intids.getId(root['multi1'])
+ >>> multi2_id = intids.getId(root['multi2'])
+ >>> multi3_id = intids.getId(root['multi3'])
+
+ >>> root['multi1'].rel = [RelationValue(multi2_id),
+ ... RelationValue(multi3_id)]
+
+We need to notify that we modified the object
+
+ >>> notify(ObjectModifiedEvent(root['multi1']))
+
+Now that this is set up, let's verify whether we can find the
+proper relations in in the catalog::
+
+ >>> len(list(catalog.findRelations({'to_id': multi2_id})))
+ 1
+ >>> len(list(catalog.findRelations({'to_id': multi3_id})))
+ 1
+ >>> len(list(catalog.findRelations({'from_id': multi1_id})))
+ 2
+
Temporary relations
===================
@@ -412,8 +461,34 @@
>>> realize_relations(root['d'])
>>> notify(ObjectModifiedEvent(root['d']))
-The relation will now show up in the catalog::
+We can see the real relation object now::
+ >>> root['d'].rel
+ <z3c.relationfield.relation.RelationValue object at ...>
+
+The relation will also now show up in the catalog::
+
>>> after2 = sorted(catalog.findRelations({'to_id': a_id}))
>>> len(after2) > len(before)
True
+
+Temporary relation values also work with ``RelationList`` objects::
+
+ >>> root['multi_temp'] = MultiItem()
+ >>> root['multi_temp'].rel = [TemporaryRelationValue('a')]
+
+Let's convert this to a real relation::
+
+ >>> realize_relations(root['multi_temp'])
+ >>> notify(ObjectModifiedEvent(root['multi_temp']))
+
+Again we can see the real relation object when we look at it::
+
+ >>> root['multi_temp'].rel
+ [<z3c.relationfield.relation.RelationValue object at ...>]
+
+And we will now see this new relation appear in the catalog::
+
+ >>> after3 = sorted(catalog.findRelations({'to_id': a_id}))
+ >>> len(after3) > len(after2)
+ True
Modified: z3c.relationfield/trunk/src/z3c/relationfield/__init__.py
===================================================================
--- z3c.relationfield/trunk/src/z3c/relationfield/__init__.py 2008-12-11 18:22:35 UTC (rev 93914)
+++ z3c.relationfield/trunk/src/z3c/relationfield/__init__.py 2008-12-11 18:31:31 UTC (rev 93915)
@@ -1,4 +1,4 @@
from z3c.relationfield.relation import RelationValue, TemporaryRelationValue
from z3c.relationfield.index import RelationCatalog
-from z3c.relationfield.schema import Relation
+from z3c.relationfield.schema import Relation, RelationList
from z3c.relationfield.event import realize_relations
Modified: z3c.relationfield/trunk/src/z3c/relationfield/event.py
===================================================================
--- z3c.relationfield/trunk/src/z3c/relationfield/event.py 2008-12-11 18:22:35 UTC (rev 93914)
+++ z3c.relationfield/trunk/src/z3c/relationfield/event.py 2008-12-11 18:31:31 UTC (rev 93915)
@@ -11,7 +11,7 @@
from zc.relation.interfaces import ICatalog
from z3c.relationfield.interfaces import (IHasRelations,
- IRelation,
+ IRelation, IRelationList,
IRelationValue,
ITemporaryRelationValue)
@@ -51,11 +51,16 @@
addRelations(obj, event)
def realize_relations(obj):
- """Given an object, convert any temporary relatiosn on it to real ones.
+ """Given an object, convert any temporary relations on it to real ones.
"""
- for name, relation in _potential_relations(obj):
+ for name, index, relation in _potential_relations(obj):
if ITemporaryRelationValue.providedBy(relation):
- setattr(obj, name, relation.convert())
+ if index is None:
+ # relation
+ setattr(obj, name, relation.convert())
+ else:
+ # relation list
+ getattr(obj, name)[index] = relation.convert()
def _setRelation(obj, name, value):
"""Set a relation on an object.
@@ -83,18 +88,26 @@
Only real relations are returned, not temporary relations.
"""
- for name, relation in _potential_relations(obj):
+ for name, index, relation in _potential_relations(obj):
if IRelationValue.providedBy(relation):
yield name, relation
def _potential_relations(obj):
- """Given an object return tuples of name, relation value.
+ """Given an object return tuples of name, index, relation value.
Returns both IRelationValue attributes as well as ITemporaryRelationValue
attributes.
+
+ If this is a IRelationList attribute, index will contain the index
+ in the list. If it's a IRelation attribute, index will be None.
"""
for iface in providedBy(obj).flattened():
for name, field in getFields(iface).items():
if IRelation.providedBy(field):
relation = getattr(obj, name)
- yield name, relation
+ yield name, None, relation
+ if IRelationList.providedBy(field):
+ l = getattr(obj, name)
+ if l is not None:
+ for i, relation in enumerate(l):
+ yield name, i, relation
Modified: z3c.relationfield/trunk/src/z3c/relationfield/interfaces.py
===================================================================
--- z3c.relationfield/trunk/src/z3c/relationfield/interfaces.py 2008-12-11 18:22:35 UTC (rev 93914)
+++ z3c.relationfield/trunk/src/z3c/relationfield/interfaces.py 2008-12-11 18:31:31 UTC (rev 93915)
@@ -1,5 +1,5 @@
from zope.interface import Interface, Attribute
-from zope.schema.interfaces import IField
+from zope.schema.interfaces import IField, IList
class IHasRelations(Interface):
"""Marker interface indicating that the object has relations.
@@ -11,6 +11,9 @@
class IRelation(IField):
pass
+class IRelationList(IList):
+ pass
+
class IRelationValue(Interface):
"""A relation between the parent object and another one.
Modified: z3c.relationfield/trunk/src/z3c/relationfield/schema.py
===================================================================
--- z3c.relationfield/trunk/src/z3c/relationfield/schema.py 2008-12-11 18:22:35 UTC (rev 93914)
+++ z3c.relationfield/trunk/src/z3c/relationfield/schema.py 2008-12-11 18:31:31 UTC (rev 93915)
@@ -3,11 +3,11 @@
from lxml import etree
from zope.interface import implements
-from zope.schema import Field
+from zope.schema import Field, List
import z3c.schema2xml
-from z3c.relationfield.interfaces import IRelation
+from z3c.relationfield.interfaces import IRelation, IRelationList
from z3c.relationfield.relation import TemporaryRelationValue
class Relation(Field):
@@ -29,3 +29,28 @@
return None
path = element.text
return TemporaryRelationValue(path)
+
+class RelationList(List):
+ implements(IRelationList)
+
+ value_type = Relation()
+
+class RelationListGenerator(grok.Adapter):
+ """Export a relation list to XML.
+ """
+ grok.context(IRelationList)
+ grok.implements(z3c.schema2xml.IXMLGenerator)
+
+ def output(self, container, value):
+ element = etree.SubElement(container, self.context.__name__)
+ field = self.context.value_type
+ if value is not None:
+ for v in value:
+ IXMLGenerator(field).output(container, v)
+
+ def input(self, element):
+ field = self.context.value_type
+ return [
+ IXMLGenerator(field).input(sub_element)
+ for sub_element in element]
+
More information about the Checkins
mailing list