我有两个通过多对多关系连接的课程:Parent
和Tag
。
Base = declarative_base()
association_table = Table('associations', Base.metadata,
Column('parent_id', Integer, ForeignKey('parent.id')),
Column('tag_id', Integer, ForeignKey('tag.id')),
)
class Tag(Base):
__tablename__ = 'tags'
id = Column(Integer, Sequence('tag_id_seq'), primary_key=True)
name = Column(String)
class Parent(Base):
__tablename__ = 'parents'
id = Column(Integer, Sequence('parent_id_seq'), primary_key=True)
tags = relationship('Tag', secondary=association_table, backref='parents')
如果我想查询与Tag
有一个或多个关系的所有Parent
个对象,我会这样做:
session.query(Tag).filter(Tag.parents.any()).all()
但是,此Parent
类是子类的父级,Alice
和Bob
:
class Alice(Parent):
__tablename__ = 'alices'
__mapper_args__ = {'polymorphic_identity': 'alice'}
alice_id = Column(Integer, ForeignKey('parents.id'), primary_key=True)
class Bob(Parent):
__tablename__ = 'bobs'
__mapper_args__ = {'polymorphic_identity': 'bob'}
bob_id = Column(Integer, ForeignKey('parents.id'), primary_key=True)
现在我希望能够检索与Tag
对象有一个或多个关系的所有Alice
个对象。上一个查询session.query(Tag).filter(Tag.parents.any()).all()
不会这样做,因为它不会区分Alice
或Bob
个对象 - 它甚至不知道它们的存在。
我已经在查询中搞砸了一段时间但没有成功,所以我假设如果可以完成,它必须与Table类中的一些额外的代码行有关如上所示。虽然文档中包含有关polymorphic classes和many-to-many relations的信息,但Mike Bayer本人也提供了一个this回答一个看似相关的问题的人,这个问题看起来很有趣,但我还远未理解,我和# 39;有点卡住了。
代码示例可能会令Python解释器感到厌恶,但希望能够得到我的观点。那些可以帮助我的人的糖果!
答案 0 :(得分:1)
在写一个小型MWE的时候,我实际上找到了一个解决方案,这实际上与我已经尝试过的几乎相同。然而,萌德给了我这种方法的新希望,谢谢:)。
from sqlalchemy import create_engine, ForeignKey, Column, String, Integer, Sequence, Table
from sqlalchemy.orm import sessionmaker, relationship, backref
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
association_table = Table('associations', Base.metadata,
Column('parent_id', Integer, ForeignKey('parents.id')),
Column('tag_id', Integer, ForeignKey('tags.id')),
)
class Tag(Base):
__tablename__ = 'tags'
id = Column(Integer, Sequence('tag_id_seq'), primary_key=True)
name = Column(String)
class Parent(Base):
__tablename__ = 'parents'
id = Column(Integer, Sequence('parent_id_seq'), primary_key=True)
tags = relationship('Tag', secondary=association_table, backref='parents')
class Alice(Parent):
__tablename__ = 'alices'
__mapper_args__ = {'polymorphic_identity': 'alice'}
alice_id = Column(Integer, ForeignKey('parents.id'), primary_key=True)
class Bob(Parent):
__tablename__ = 'bobs'
__mapper_args__ = {'polymorphic_identity': 'bob'}
bob_id = Column(Integer, ForeignKey('parents.id'), primary_key=True)
engine = create_engine("sqlite://")
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()
tag_a = Tag(name='a')
tag_b = Tag(name='b')
tag_c = Tag(name='c')
session.add(tag_a)
session.add(tag_b)
session.add(tag_c)
session.commit()
session.add(Alice(tags=[tag_a]))
session.add(Bob(tags=[tag_b]))
session.commit()
for tag in session.query(Tag).\
filter(Tag.parents.any(Parent.id == Alice.alice_id)).\
all():
print(tag.name)
如果有一个很好的替代方法,我仍然感兴趣。我可以想象sqlalchemy提供更直接和优雅的方法,以便人们可以做到,例如:
for tag in session.query(Tag).\
filter(Tag.alices.any()).\
all():
print(tag.name)
答案 1 :(得分:1)
如果以某种方式编写对象类,可以使用钝力方法...只需搜索它们......有点像粗略的查询方法:
all_tag_objects = session.query(Tag).all() ## All tag objects in your database
tags = []
for tag in all_tag_objects:
for parent in tag.parents:
if parent.alices != []: ## If there are alice objects in the tag parents alice reltionship instance variable...Then we append the tag because it meets our criteria.
flagged_tags.append(tag)
听起来你找到了更好的方法,但我想最终的测试是实际进行速度测试。