In a many-to-many relationship, I have some extra data on the association table to describe the relationship (a quantity and a boolean value). I’d like to use a mapped collection to avoid working directly with the association objects, but I can’t figure out how to use a tuple for the values in the mapping. As far as I can tell, Attribute as dict of lists using middleman table with SQLAlchemy is similar, but backwards.
To illustrate this, I want to do something like this:
>>> collection.items[item] = (3, True)
>>> collection.items[item] = (1, False)
>>> colletion.items
{"item name": (3, True), "item name": (1, False)}
This… works… but eventually SQLAlchemy tries to put the tuple into the database (I’ll try to recreate that in a bit).
I have also tried using tuples in the key (the related object and one of the other columns), but it looks terrible, and it doesn’t work:
>>> collection.items[item, True] = 3
>>> collection.items[item, False] = 1
>>> collection.items
{(<item>, True): 3, (<item>, False): 1}
I can put the item name and one value in the mapped collection without issue: I had another (structurally identical) form of this relationship which I solved by making two relationships (and association proxies) that divided the association table between them based on the boolean value, and their creator functions set the boolean correctly without any further interference. Unfortunately, in that case the boolean specified a minor semantic difference (application code needs to treat the items as a group), while in the current problem it is a not insignificant cosmetic difference (application code should not treat the items as groups, but the value does alter how the item is displayed and so is needed).
the linked answer has all the components. attribute_mapped_collection and association_proxy can do lots together. First here is the dictionary of string->tuple(int, boolean) (updated for m2m):
Here it is the other way around with the tuples on the association and the name on the endpoint:
that’s probably all you need. If you’re using Postgresql, which supports SQL tuples, you can add more to the above using hybrids plus
tuple_(), so thatas_tuplecan be used at the SQL level also (below also uses one-to-many instead of association object just for example):