查询通过多对多关系过滤的多个连接的继承表

时间:2012-11-18 13:29:34

标签: sqlalchemy flask-sqlalchemy

我有一个SQLAlchemy方案,看起来大致如下:

participation = db.Table('participation',
        db.Column('artist_id', db.Integer, db.ForeignKey('artist.id'),
                  primary_key=True),
        db.Column('song_id', db.Integer, db.ForeignKey('song.id'),
                  primary_key=True),
)

class Streamable(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    kind = db.Column(db.String(10), nullable=False)
    score = db.Column(db.Integer, nullable=False)
    __mapper_args__ = {'polymorphic_on': kind}

class Artist(Streamable):
    id = db.Column(db.Integer, db.ForeignKey('streamable.id'), primary_key=True)
    name = db.Column(db.Unicode(128), nullable=False)
    __mapper_args__ = {'polymorphic_identity': 'artist'}

class Song(Streamable):
    id = db.Column(db.Integer, db.ForeignKey('streamable.id'), primary_key=True)
    name = db.Column(db.Unicode(128), nullable=False)
    artists = db.relationship("Artist", secondary=participation,
                              backref=db.backref('songs'))
    __mapper_args__ = {'polymorphic_identity': 'song'}

class Video(Streamable):
    id = db.Column(db.Integer, db.ForeignKey('streamable.id'), primary_key=True)
    song_id = db.Column(db.Integer, db.ForeignKey('song.id'), nullable=False)
    song = db.relationship('Song', backref=db.backref('videos', lazy='dynamic'),
                           primaryjoin="Song.id==Video.song_id")
    __mapper_args__ = {'polymorphic_identity': 'video'}

我想对有特定艺术家的歌曲或视频进行单一查询;即,一个查询中的这两个查询(所有查询应为.order_by(Streamable.score)):

q1=Streamable.query.with_polymorphic(Video)
q1.join(Video.song, participation, Artist).filter(Artist.id==1)
q2=Streamable.query.with_polymorphic(Song)
q2.join(participation, Artist).filter(Artist.id==1)

这是我达到的最好成绩;它会发出怪异的SQL并且总是产生空结果(不确定原因):

p1=db.aliased(participation)
p2=db.aliased(participation)
a1=db.aliased(Artist)
a2=db.aliased(Artist)
q=Streamable.query.with_polymorphic((Video, Song))
q=q.join(p1, a1).join(Video.song, p2, a2)
q.filter(db.or_((a1.id==1), (a2.id==1))).order_by('score')

执行此查询的正确方法是什么(如果有的话(可能关系数据存储区不适合我的工作......)?

1 个答案:

答案 0 :(得分:1)

您的查询基本上是正确的。我认为从joinouterjoin的更改应解决问题:

q=q.outerjoin(p1, a1).outerjoin(Video.song, p2, a2)

我还会将order_by替换为:

q = q.order_by(Streamable.score)