如何在SQLAlchemy ORM中查询多对多关系?

时间:2019-07-07 10:34:54

标签: python orm sqlalchemy

我知道这个问题已经被问过几次了,但是结果都没有帮助。

我在表格音轨和流派之间存在多对多关系,如下所示:

track_genres = Table('track_genres',
                     Base.metadata,
                     Column('tracks_id', INTEGER, ForeignKey('tracks.id'), primary_key=True),
                     Column('genres_id', INTEGER, ForeignKey('genres.id'), primary_key=True)
                     )

class Genre(Base):
    __tablename__ = 'genres'
    id = Column(INTEGER, primary_key=True, unique=True, autoincrement=True, nullable=False)
    name = Column(TEXT)


class Track(Base):
    __tablename__ = 'tracks'
    id = Column(INTEGER, primary_key=True, unique=True, autoincrement=True, nullable=False)
    name = Column(TEXT)
    album_id = Column(INTEGER, ForeignKey('albums.id'))
    genres = orm.relationship('Genre', secondary=track_genres, backref=orm.backref('tracks', lazy='dynamic',cascade='all'))

据我所知,这些关系已正确声明,因为我在track_genres表中具有以下关系:

tracks_id | genres_id
---------------------
1         | 1        
1         | 2        
1         | 3        
1         | 4        
2         | 1        
2         | 2        
2         | 3        
2         | 4        
3         | 5        
3         | 6        
3         | 7        

现在,问题是,当我执行当前查询时

    query = session.query(
        Track,
        Genre.name.label('genre_name')
    ).filter(
        Track.genres.any(id=Genre.id)
    )

我得到的结果包括所有数据排列,因此ID为1的轨道将被查询返回7次(每种流派ID从1到7一次),即使仅返回4次(因为ID为1:1-1、1-2、1-3、1-4的轨道只有4种关系)

我该如何在查询中编写过滤器/联接,以便查询仅返回正确的结果(在这种情况下,对于ID = 1的跟踪,四行),而不是进行所有可能的排列?

2 个答案:

答案 0 :(得分:0)

经过进一步的实验,我相信正确的方法是从轨道中加入各自的关系:

    query = session.query(
        Track,
        Genre.name.label('genre_name')
    ).join.(
        Track.genres
    )

答案 1 :(得分:0)

或者,您可以尝试使用 contains()过滤您的查询。

db.session.query(Track).filter(
    Track.genres.contains(genre_obj), 
    Track.genres.contains(genre_obj2),
    # And so on...
)