[Zope-dev] RFC: RelationAware class for relations between objects
Shane Hathaway
shane@zope.com
Fri, 02 May 2003 09:47:37 -0400
Roch=E9 Compaan wrote:
> On Thu, 1 May 2003 23:30:04 +0200
> Roch=E9 Compaan <roche@upfrontsystems.co.za> wrote:
>=20
>=20
>>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 ...
>=20
>=20
> 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 object=
s
> use relationships.
The work you did looks good, but at this point I'd still like to call=20
the work you did a proof of concept. The next step is to write a=20
proposal that others can comment on. A long discussion like this is=20
hard for others to follow, but a proposal sums up everything we learned.
> 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.
One request: the word "relation" should not appear anywhere in the API.=20
We should use "relationship" consistently. I'm pretty sure that=20
relations are only one possible implementation of relationship storage.
> 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.
We can't make the assumption that all objects have IDs. One of the=20
requirements is that either direct or indirect references are possible.=20
All of the requirements should be listed on the proposal.
> I do not define Relationships as static attributes since we need a hand=
le on
> the class instance to relate.
That's what computed attributes and descriptors are for.
> from Relations import Relations # This is the Relations class in mxmRel=
ations
> import ExtensionClass
> from ComputedAttribute import ComputedAttribute
>=20
> class Relationship(ExtensionClass.Base):
>=20
> def __init__(self, ob, relation, cardinality):
> self.ob =3D ob
> self.relation =3D relation
> self.cardinality =3D cardinality
>=20
> _r_ =3D ComputedAttribute(lambda self: self.relation._get(self.ob))
Actually, I meant for this class to be a ComputedAttribute/descriptor.=20
This class does not need to use computed attributes.
>=20
> def __getattr__(self, name):
> l =3D self._r_
> if self.cardinality =3D=3D '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 =3D=3D name:
> return ob
>=20
> def add(self, other):
> # TODO: test if 'other' is not a sequence if our cardinality is
> # single
> self.relation._relate(self.ob, other)
>=20
> def remove(self, other):
> self.relation._unrelate(self.ob, other)
>=20
>=20
> student_courses =3D Relations()
> term_courses =3D Relations()
> # this relation will be between an object that knows it relationships a=
nd=20
> # instances of third party objects that doesn't
> school_courses =3D Relations()
Note that you did not arrange for the relations to be stored in ZODB at=20
all. I'll help you deal with that once we've prepared an API.
If you have some time, I'd appreciate it if you started a proposal on a=20
wiki page. Then we'll come up with an API. Once we're satisfied with=20
the API, we'll ask for comments.
Shane