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