Sqlalchemy:查询m2m关系的多态类

时间:2015-08-20 02:50:37

标签: python sqlalchemy

我有两个通过多对多关系连接的课程:ParentTag

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类是子类的父级,AliceBob

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()不会这样做,因为它不会区分AliceBob个对象 - 它甚至不知道它们的存在。

我已经在查询中搞砸了一段时间但没有成功,所以我假设如果可以完成,它必须与Table类中的一些额外的代码行有关如上所示。虽然文档中包含有关polymorphic classesmany-to-many relations的信息,但Mike Bayer本人也提供了一个this回答一个看似相关的问题的人,这个问题看起来很有趣,但我还远未理解,我和# 39;有点卡住了。

代码示例可能会令Python解释器感到厌恶,但希望能够得到我的观点。那些可以帮助我的人的糖果!

2 个答案:

答案 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)

听起来你找到了更好的方法,但我想最终的测试是实际进行速度测试。