Reputation: 31
In the Flask sqlalchemy documentation an example of using a simple many to many relationship is given:
tags = db.Table('tags',
db.Column('tag_id', db.Integer, db.ForeignKey('tag.id')),
db.Column('page_id', db.Integer, db.ForeignKey('page.id'))
)
class Page(db.Model):
id = db.Column(db.Integer, primary_key=True)
tags = db.relationship('Tag', secondary=tags,
backref=db.backref('pages', lazy='dynamic'))
class Tag(db.Model):
id = db.Column(db.Integer, primary_key=True)
Where one can use the following syntax to reach out to the related objects:
Page.tags
What I am trying to accomplish is basically to add the relationship below to the one above:
tag_children = db.Table('tag_children,',
db.Column('parent_id', db.Integer, db.ForeignKey('tags.tag_id')),
db.Column('child_id', db.Integer, db.ForeignKey('tags.tag_id'))
)
So that each page has tags attached to it, but each tag can have multiple children in the scope of that page. I've made a show case for a Page called cars below where I have it's tags and their respective children tags.
(Page) Cars:
All the list items above are tag objects
I want to be able to use the following syntax bellow to get the related objects:
Page.tag.children
For instance (obvously dummy code below, but I want to be clear about what the intended purpose of the relationship is):
Cars.tesla.children
Upvotes: 3
Views: 869
Reputation: 578
I think, you don't need another table for tag_children
. Try to use SQLAlchemy Adjacency Lists:
class Tag(db.Model):
id = db.Column(db.Integer, primary_key=True)
parent_id = Column(Integer, ForeignKey('tag.id'))
children = relationship("Tag",
backref=backref('parent', remote_side=[id])
)
With this schema you may use syntax like:
for tag in page.tags: # where page is a Page instance received from db
print tag.children
It is a common syntax for working with SQLAlchemy models. Try to use it instead of the proposed Cars.tesla.children
.
Something like Cars['tesla'].children
may be implemented via getitem method, but i think, it's very unclear way.
Full code snippet:
class Page(Base):
__tablename__ = 'page'
id = Column(Integer, primary_key=True)
name = Column(String(256))
tags = relationship('Tag', secondary='tags',
backref=backref('pages', lazy='dynamic'))
def __str__(self):
return self.name
class Tag(Base):
__tablename__ = 'tag'
id = Column(Integer, primary_key=True)
name = Column(String(256))
parent_id = Column(Integer, ForeignKey('tag.id'))
children = relationship(
"Tag",
backref=backref('parent', remote_side=[id])
)
def __str__(self):
return self.name
class Tags(Base):
__tablename__ = 'tags'
tag_id = Column(Integer, ForeignKey('tag.id'), primary_key=True)
page_id = Column(Integer, ForeignKey('page.id'), primary_key=True)
And test case:
# Create page and tags
session.add(Page(id=1, name="cars"))
session.add(Tag(id=1, name="Mercedes"))
session.add(Tag(id=2, name="A-series", parent_id=1))
session.add(Tag(id=3, name="B-series", parent_id=1))
session.add(Tag(id=4, name="C-series", parent_id=1))
session.add(Tag(id=5, name="Tesla"))
session.add(Tag(id=6, name="Tesla Roadster", parent_id=5))
session.add(Tag(id=7, name="Model X", parent_id=5))
session.add(Tag(id=8, name="Model S", parent_id=5))
session.add(Tag(id=9, name="Model 3", parent_id=5))
# Fill relation
session.add(Tags(tag_id=1, page_id=1))
session.add(Tags(tag_id=5, page_id=1))
session.commit()
print session.query(Page).get(1) # >>> cars
print session.query(Page).get(1).tags # >>> Mercedes, Tesla
print session.query(Page).get(1).tags[1].children # >>> Tesla models
Upvotes: 1