In my model, I have a base object class A which holds a set of attributes. Each object of A can be connected to any other object of A through a many-to-many association object Context. This Context class holds a key for every connection.
class A(Base):
__tablename__ = "a"
id = Column(Integer, primary_key=True)
# other attributes
value = Column(Integer)
def __init__(self, value):
self.value = value
class Context(Base):
__tablename__ = "context"
holder_id = Column(Integer, ForeignKey("a.id"), nullable=False, primary_key=True)
attachment_id = Column(Integer, ForeignKey("a.id"), nullable=False, primary_key=True)
key = Column(String, primary_key=True)
holder = relationship(A,
primaryjoin=lambda: Context.holder_id==A.id)
attachment = relationship(A,
primaryjoin=lambda: Context.attachment_id==A.id)
The Context class therefore stores 3-tuples of the form ‘Holder object a1 holds attachment a2 with key k1’.
I now want to have a smart proxy collection on A which groups this relationship on the Context.key such that I can use it as follows:
a1 = A(1)
a1.context["key_1"] = set([A(2)])
a1.context["key_2"] = set([A(3), A(4), A(5)])
a1.context["key_1"].add(A(10))
a100 = A(100)
a100.context = {
"key_1": set([A(101)])
}
How do I have to define context?
I know there is an example for modelling a dict–set proxy in the SQLAlchemy documentation but somehow I am not able to get it to work in a self-referential situation.
Unless I’m blanking a bit (which is possible…gin…) this can’t be done with association proxy directly on the relationship because a1.context would need to be a collection where each element has a unique key, then the collection can be a dictionary – but there is no such collection here, as a1 can have many Context objects with the same key. Assoc prox’s simple way of reducing a collection of objects to a collection of an attribute on each member object doesn’t apply to this.
So if you really want this, and your structure can’t change, just do what association proxy does, just in a hardcoded way, which is, build a proxying collection ! actually two, I think. Not too big a deal, just need to turn the crank….quite a bit, make sure you add tests for every manipulation here: