Multiple Associated Properties
See ticket #19.
Currently, Dejavu only supports automatically relating two classes via a single pair of properties. That is, given classes A and B, you can relate A.ID to B.Name, but you can't relate A.ID to B.Name and B.Nickname, for example.
It's not worth the effort or complexity to support multiple associations to the same far class; that would require that the nearKey and farKey attributes of UnitAssociation? objects be arbitrary, and that's too difficult to support (see storage.db.StorageManagerDB.join, for an example which relies on the singularity, and storeshelve is much worse).
I've found it's just as easy to fake the builtin behavior (one might say the builtin behavior is faking pure Python). I'll use the example of a Directory class which needs to be related to itself via an intermediate Relation class. Rather than using associate(), it's done by hand; here are the relevant bits of the Directory and Relation classes:
class Directory(Unit): """A Unit representing an entry in a Directory.""" FullName = UnitProperty() Gender = UnitProperty() def Relation(self, expr=None): """Recall opposite 'Relation' Units.""" f = logic.Expression(lambda x: x.Left == self.ID or x.Right == self.ID) if expr is not None: f += expr return self.sandbox.recall(Relation, f) class Relation(Unit): """Represents a Relation between two Directory Units.""" Left = UnitProperty(int) LeftType = UnitProperty() Right = UnitProperty(int) RightType = UnitProperty() ContactType = UnitProperty() def Directory(self, expr=None): """Recall opposite 'Directory' Units.""" f = logic.Expression(lambda x: x.ID in (self.Left, self.Right)) if expr is not None: f += expr return self.sandbox.recall(Directory, f)
...and here's a custom UnitAssociation? to recall all Directory records that are related to a given Directory:
class RelationAssociation(dejavu.UnitAssociation): """Unit Association for use between Directory records with Relations.""" to_many = True def related(self, unit, expr=None): value = getattr(unit, self.nearKey) if value is None: return [] f = logic.filter(**{self.farKey: value}) if expr is not None: f += expr units = {} for rel in unit.sandbox.xrecall(Relation, logic.filter(Left=unit.ID)): dir = unit.sandbox.unit(Directory, ID=rel.Right) if dir: units[dir] = None for rel in unit.sandbox.xrecall(Relation, logic.filter(Right=unit.ID)): dir = unit.sandbox.unit(Directory, ID=rel.Left) if dir: units[dir] = None return units.keys() Directory.associate(u'ID', Directory, u'ID', RelationAssociation, RelationAssociation)
