[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