Python SQLAlchemy:过滤多对一关系,其中一个对象具有包含特定值的列表
我有一些这样的表格:Python SQLAlchemy:过滤多对一关系,其中一个对象具有包含特定值的列表,python,sqlalchemy,flask-sqlalchemy,Python,Sqlalchemy,Flask Sqlalchemy,我有一些这样的表格: class Genre(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(128), index=True) artist_id = db.Column(db.Integer, db.ForeignKey('artist.id')) class Song(db.Model): id = db.Column(db.Integer
class Genre(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(128), index=True)
artist_id = db.Column(db.Integer, db.ForeignKey('artist.id'))
class Song(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(128), index=True)
artist = db.relationship('Artist', uselist=False)
artist_id = db.Column(db.Integer, db.ForeignKey('artist.id'))
class Artist(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(128), index=True)
genres = db.relationship('Genre')
songs = db.relationship('Song')
所以基本上,歌曲只有一个艺术家。每个艺术家可以有多种风格
我试图得到任何一个艺术家的所有歌曲,他的流派列表包含一个特定名称的流派。我做了一些研究,发现了一些非常接近的东西:
Song.query.filter(Artist.genres.any(Genre.name.in_([genre_name_im_looking_for])))
这将是一种工作,但不是所有情况下。例如,上述声明还将返回所有具有“独立摇滚”类型的艺术家的歌曲。如何指定我不希望流派名称在值列表中,而是希望它是一个特定的值
Song.query.filter(Artist.genres.any(Genre.name='rock'))
也不可能,因为它是一个关键字表达式
有什么想法吗?经过进一步的研究,我找到了解决这个问题的一种方法,尽管与我想要的有点不同 首先,为了获得所有包含特定流派的艺术家,我执行了:
artists = Artist.query.filter(
Artist.genres.any(Genre.name.like('genre_name'))).all()
然后,我迭代了每个艺术家,并通过在过滤器中将艺术家用作关键字表达式来查询歌曲模型,如下所示:
for a in artist:
most_common_genre_songs = Song.query.filter_by(artist=a).all()
我不确定是否有更有效的方法来打这个电话,或者用一行的方式(我打赌有),但现在,这就可以了。使用此测试数据:
# Test Data
artists = [
Artist(
name='should match rock',
genres=[Genre(name='rock'), Genre(name='pop')],
songs=[Song(name='love'), Song(name='hate')]
),
Artist(
name='should NOT match',
genres=[Genre(name='indie rock')],
songs=[Song(name='elsewhere')]
),
]
db.session.add_all(artists)
db.session.commit()
下面的查询应满足您的要求:
q = Song.query.filter(Song.artist.has(Artist.genres.any(Genre.name == 'rock')))
assert len(q.all()) == 2
它不应该是
Song.query.filter(Artist.genres.any(Genre.name=='rock'))
?(比较而非赋值)@Wash是正确的,但即使是[rock]中的也不应该真正匹配独立摇滚
。也许你的艺术家既有摇滚
又有独立摇滚
流派。@van是的,我认为两者都不应该匹配。我检查了我的数据库。。。这位艺术家没有摇滚乐,但有很多以“摇滚乐”为名的流派,比如“独立摇滚乐”。还是不明白为什么它是匹配的。@Wash谢谢,我稍后再试。通常可以使用表达式,比如Artist.query.filter_by(name='whatever'),所以我甚至没有考虑使用比较。对sqlalchemy这个行业还是新手。@van,我试过你的问题,但我仍然发现艺术家们的流派列表中有“独立摇滚”,但没有“摇滚”。我已经检查过了,这位艺术家没有两种风格。这正是我想要的,谢谢。快速提问,我还有另一个表,Users,它与歌曲有一对多的关系,我现在希望增加您建议的查询,以过滤属于特定用户的歌曲。此查询工作Song.query.filter(Song.artist.has(artist.genres.any(Genre.name='Genre')).filter(Song.user==some\u user\u object)。all()
交换筛选器语句会对性能产生什么样的影响?我认为在任何现代RDBMS中都不会有任何性能差异。很好的解决方案。谢谢,@AlexF。