[Zope-dev] RFC: RelationAware class for relations between
objects
Roché Compaan
roche@upfrontsystems.co.za
Fri, 2 May 2003 13:58:42 +0200
On Thu, 1 May 2003 23:30:04 +0200
Roché Compaan <roche@upfrontsystems.co.za> wrote:
> Something like ComputedAttribute or descriptors should make it possible.
> Hmm, I might just have thought of a way to do this with
> ComputedAttribute which I'll try tomorrow. But ComputedAttribute is
> Zope2 specific isn't it? Darn ...
It looks like ComputedAttribute has no dependencies on Zope 2 code so I
had a go at another API addressing specifically the way in which objects
use relationships.
I used the Relations class in mxmRelations as is since it has no Zope
dependencies. How this will be made accessible as a different branch in
the ZODB (iow where it will be stored and how you will locate it) and
how the Relations API must be extended still needs to be addressed.
I assume all objects have ids. This is not a requirement and if we drop
this assumption very little in the implementation have to change. I do
not define Relationships as static attributes since we need a handle on
the class instance to relate.
from Relations import Relations # This is the Relations class in mxmRelations
import ExtensionClass
from ComputedAttribute import ComputedAttribute
class Relationship(ExtensionClass.Base):
def __init__(self, ob, relation, cardinality):
self.ob = ob
self.relation = relation
self.cardinality = cardinality
_r_ = ComputedAttribute(lambda self: self.relation._get(self.ob))
def __getattr__(self, name):
l = self._r_
if self.cardinality == 'single':
return getattr(l[0], name)
else:
# This can optimised: Relations can return a BTree that we
# can subscript
for ob in l:
if ob.id == name:
return ob
def add(self, other):
# TODO: test if 'other' is not a sequence if our cardinality is
# single
self.relation._relate(self.ob, other)
def remove(self, other):
self.relation._unrelate(self.ob, other)
student_courses = Relations()
term_courses = Relations()
# this relation will be between an object that knows it relationships and
# instances of third party objects that doesn't
school_courses = Relations()
class Student:
def __init__(self, id, name):
self.id = id
self.name = name
self.courses = Relationship(self, student_courses, 'multiple')
class Course:
def __init__(self, id, name):
self.id = id
self.name = name
self.students = Relationship(self, student_courses, 'multiple')
self.school = Relationship(self, school_courses, 'single')
class Term:
def __init__(self, id, name):
self.id = id
self.name = name
self.courses = Relationship(self, term_courses, 'multiple')
# This is a third party class
class School:
def __init__(self, id, name):
self.id = id
self.name = name
john = Student('john', 'John Smith')
peter = Student('peter', 'Peter Pan')
mary = Student('mary', 'Mary Scary')
susan = Student('susan', 'Susan')
python101 = Course('python101', 'Python 101')
zope101 = Course('zope101', 'Zope 101')
law = School('law', 'Law')
compsci = School('compsci', 'Computer Science')
python101.students.add(john)
python101.students.add(peter)
python101.school.add(compsci)
zope101.students.add(mary)
zope101.students.add(peter)
zope101.school.add(compsci)
assert john.courses.python101.name == "Python 101"
assert mary.courses.zope101.name == "Zope 101"
assert python101.school.name == "Computer Science"
# Teach compsci about relationships
compsci.courses = Relationship(compsci, school_courses, 'multiple')
assert compsci.courses.python101.name == "Python 101"
# Changing attributes on related objects
python101.school.name = "Computer Science School"
zope101.students.mary.name = "Mary Airy"
--
Roché Compaan
Upfront Systems http://www.upfrontsystems.co.za