I have came to an answer with the help of agronholm from #sqlalchemy at freenode. (thank you!)
SQLAlchemy already predicts this kind of situations (wanting a getter/setter for a relationship)
http://docs.sqlalchemy.org/en/rel_0_9/orm/extensions/associationproxy.html
There is even the very specific case of my question documented with an example: http://docs.sqlalchemy.org/en/rel_0_9/orm/extensions/associationproxy.html#simplifying-association-objects
So, as to question 1, the answer is association proxies. By implementing it, the queries I made before converting the relationship from secondary to using an Association Object just work with no changes. To order the results as I needed, there is an order_by
keyword.
For question 2, there are also keywords: cascade='all, delete-orphan'
Here is the full result:
class Node(db.Model):
id = db.Column(db.Integer, primary_key = True)
...
assets = association_proxy('node_assets', 'asset')
def __str__(self):
return self.name
class Asset(db.Model):
id = db.Column(db.Integer, primary_key=True)
...
nodes = association_proxy('asset_nodes', 'node')
def __str__(self):
return self.name
# Create Many to Many table with extra field
class NodesAssets(db.Model):
order = db.Column('order', db.Integer)
node_id = db.Column(db.Integer, db.ForeignKey('node.id'), primary_key = True)
node = db.relationship(Node, backref=db.backref('node_assets', order_by=order, cascade='all, delete-orphan'))
asset_id = db.Column(db.Integer, db.ForeignKey('asset.id'), primary_key = True)
asset = db.relationship(Asset, backref=db.backref('asset_nodes', cascade='all, delete-orphan'))
def __str__(self):
return "Nodes-Assets %s-%s" % (self.node, self.asset,)
However, not everything went well :(
While this is everything I wanted for the frontend, the backend with flask-admin is having some problems:
- I wanted to have the Association table as an inline model for the Assets and Nodes, but that is currently not possible, because of lack of support for tables with multiple primary keys: flask-admin/issues/505
- Forgetting the inline model part and just having the field there is also not possible: flask-admin/issues/236