[Checkins] SVN: z3c.relationfield/trunk/ * introduce RelationChoice field

Martijn Faassen faassen at infrae.com
Tue Feb 10 14:16:05 EST 2009


Log message for revision 96409:
  * introduce RelationChoice field
  
  * clarify way comparing and sorting is done for RelationValue
  

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/interfaces.py
  U   z3c.relationfield/trunk/src/z3c/relationfield/relation.py
  U   z3c.relationfield/trunk/src/z3c/relationfield/schema.py

-=-
Modified: z3c.relationfield/trunk/CHANGES.txt
===================================================================
--- z3c.relationfield/trunk/CHANGES.txt	2009-02-10 19:05:30 UTC (rev 96408)
+++ z3c.relationfield/trunk/CHANGES.txt	2009-02-10 19:16:04 UTC (rev 96409)
@@ -4,8 +4,15 @@
 0.4 (unreleased)
 ================
 
-* ...
+* Introduce a ``RelationChoice`` field that behaves like
+  ``schema.Choice`` but tracks relations. In combination with a source
+  (such as created by ``RelationSourceFactory`` provided by
+  ``z3c.relationfieldui``) this can be used to create drop-down
+  selections for relations.
 
+* Clarify the way comparing and sorting of ``RelationValue`` objects is 
+  done in order to better support choice support.
+
 0.3.2 (2009-01-21)
 ==================
 

Modified: z3c.relationfield/trunk/src/z3c/relationfield/README.txt
===================================================================
--- z3c.relationfield/trunk/src/z3c/relationfield/README.txt	2009-02-10 19:05:30 UTC (rev 96408)
+++ z3c.relationfield/trunk/src/z3c/relationfield/README.txt	2009-02-10 19:16:04 UTC (rev 96409)
@@ -218,6 +218,35 @@
   >>> root['b'].rel.from_path
   u'b'
 
+Comparing and sorting relations
+===============================
+
+Let's create a bunch of ``RelationValue`` objects and compare them::
+
+  >>> rel_to_a = RelationValue(a_id)
+  >>> b_id = intids.getId(root['b'])
+  >>> rel_to_b = RelationValue(b_id)
+  >>> rel_to_a == rel_to_b
+  False
+
+Relations of course are equal to themselves::
+
+  >>> rel_to_a == rel_to_a
+  True
+
+A relation that is stored is equal to a relation that isn't stored yet::
+
+  >>> root['b'].rel == rel_to_a
+  True
+
+We can also sort relations::
+
+  >>> [(rel.from_path, rel.to_path) for rel in
+  ...  sorted([root['b'].rel, rel_to_a, rel_to_b])]
+  [('', u'a'), ('', u'b'), (u'b', u'a')]
+
+
+
 Relation queries
 ================
 
@@ -471,6 +500,41 @@
   >>> b.rel == None
   False
 
+RelationChoice
+==============
+
+A ``RelationChoice`` field is much like an ordinary ``Relation`` field
+but can be used to render a special widget that allows a choice of
+selections.
+
+We will first demonstrate a ``RelationChoice`` field has the same effect
+as a ``Relation`` field itself::
+
+  >>> from z3c.relationfield import RelationChoice
+  >>> class IChoiceItem(Interface):
+  ...   rel = RelationChoice(title=u"Relation", values=[])
+  >>> class ChoiceItem(Persistent):
+  ...   implements(IChoiceItem, IHasRelations)
+  ...   def __init__(self):
+  ...     self.rel = None
+
+Let's create an object to point the relation to::
+
+  >>> root['some_object'] = Item()
+  >>> some_object_id = intids.getId(root['some_object'])
+
+And let's establish the relation::
+
+  >>> choice_item = ChoiceItem()
+  >>> choice_item.rel = RelationValue(some_object_id)
+  >>> root['choice_item'] = choice_item
+
+We can query for this relation now::
+
+  >>> l = sorted(catalog.findRelations({'to_id': some_object_id}))
+  >>> l
+  [<z3c.relationfield.relation.RelationValue object at ...>]
+
 RelationList
 ============
 

Modified: z3c.relationfield/trunk/src/z3c/relationfield/__init__.py
===================================================================
--- z3c.relationfield/trunk/src/z3c/relationfield/__init__.py	2009-02-10 19:05:30 UTC (rev 96408)
+++ z3c.relationfield/trunk/src/z3c/relationfield/__init__.py	2009-02-10 19:16:04 UTC (rev 96409)
@@ -2,5 +2,5 @@
                                         TemporaryRelationValue,
                                         create_relation)
 from z3c.relationfield.index import RelationCatalog
-from z3c.relationfield.schema import Relation, RelationList
+from z3c.relationfield.schema import Relation, RelationChoice, RelationList
 from z3c.relationfield.event import realize_relations

Modified: z3c.relationfield/trunk/src/z3c/relationfield/interfaces.py
===================================================================
--- z3c.relationfield/trunk/src/z3c/relationfield/interfaces.py	2009-02-10 19:05:30 UTC (rev 96408)
+++ z3c.relationfield/trunk/src/z3c/relationfield/interfaces.py	2009-02-10 19:16:04 UTC (rev 96409)
@@ -25,10 +25,16 @@
     """
 
 class IRelation(IField):
-    pass
+    """Simple one to one relations.
+    """
 
+class IRelationChoice(IRelation):
+    """A one to one relation where a choice of target objects is available.
+    """
+
 class IRelationList(IList):
-    pass
+    """A one to many relation.
+    """
 
 class IRelationValue(Interface):
     """A relation between the parent object and another one.

Modified: z3c.relationfield/trunk/src/z3c/relationfield/relation.py
===================================================================
--- z3c.relationfield/trunk/src/z3c/relationfield/relation.py	2009-02-10 19:05:30 UTC (rev 96408)
+++ z3c.relationfield/trunk/src/z3c/relationfield/relation.py	2009-02-10 19:16:04 UTC (rev 96409)
@@ -57,6 +57,23 @@
     def to_interfaces_flattened(self):
         return _interfaces_flattened(self.to_interfaces)
 
+    def __eq__(self, other):
+        if not isinstance(other, RelationValue):
+            return False
+        self_sort_key = self._sort_key()
+        other_sort_key = other._sort_key()
+        # if one of the relations we are comparing doesn't have a source
+        # yet, only compare targets. This is to make comparisons within
+        # ChoiceWidget work; a stored relation would otherwise not compare
+        # equal with a relation generated for presentation in the UI
+        if self_sort_key[0] is None or other_sort_key[0] is None:
+            return self_sort_key[-1] == other_sort_key[-1]
+        # otherwise do a full comparison
+        return self_sort_key == other_sort_key
+
+    def __neq__(self, other):
+        return not self.__eq__(other)
+
     def __cmp__(self, other):
         if other is None:
             return cmp(self._sort_key(), None)

Modified: z3c.relationfield/trunk/src/z3c/relationfield/schema.py
===================================================================
--- z3c.relationfield/trunk/src/z3c/relationfield/schema.py	2009-02-10 19:05:30 UTC (rev 96408)
+++ z3c.relationfield/trunk/src/z3c/relationfield/schema.py	2009-02-10 19:16:04 UTC (rev 96409)
@@ -3,11 +3,11 @@
 from lxml import etree
 
 from zope.interface import implements
-from zope.schema import Field, List
+from zope.schema import Field, List, Choice
 
 from z3c.schema2xml import IXMLGenerator
 
-from z3c.relationfield.interfaces import IRelation, IRelationList
+from z3c.relationfield.interfaces import IRelation, IRelationChoice, IRelationList
 from z3c.relationfield.relation import TemporaryRelationValue
 
 class Relation(Field):
@@ -34,7 +34,10 @@
     implements(IRelationList)
 
     value_type = Relation()
-    
+
+class RelationChoice(Choice):
+    implements(IRelationChoice)
+
 class RelationListGenerator(grok.Adapter):
     """Export a relation list to XML.
     """



More information about the Checkins mailing list