在使用flask的python应用程序中充分发挥sqlalchemy的潜力,理解多对一关系的工作原理以及如何利用它们,我遇到了一些麻烦。
我正在使用歌曲和艺术家的数据库,其模式如下:
CREATE TABLE song (
id INTEGER PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(64),
artist_id INTEGER
);
CREATE TABLE artist (
id INTEGER PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(64)
);
或者,通过炼金术,它看起来是这样的:
class Song(db.Model):
id = db.Column(db.Integer, primary_key=True)
kws_id = db.Column(db.String(32))
name = db.Column(db.String(255))
artist_id = db.Column(db.Integer, db.ForeignKey('artist.id'))
artist = db.relationship('Artist', backref='songs', foreign_keys=[artist_id])
class Artist(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(255))
``` `song.artist_id` 指列 `artist.id` ; 这是一个多对一的关系,许多歌曲可以指一个艺术家。
我希望我能将结果显示为:
artist:
song1
song2
song3
artist2:
song4
song5
...
或者,在json中,大致是: `{artist: [song1, song2, song3], artist2: [song4, song5]}` . (最终的目标是通过flask以ajax分页响应的形式返回它。
基本上,我希望我能有一个包含歌曲列表的艺术家目录;如果我对一首特定的歌曲进行搜索,它会返回一个结构相同的dict,只有匹配的歌曲。
如果我想运行一个查询并选择来自所有艺术家的所有歌曲,我可以简单地查询所有艺术家,然后使用 `backref` 属性获取所有歌曲。
artists = Artist.query.all()
for artist in artists:
songs = artist.songs
construct json: artist => song
然而,我正在努力寻找一种解决方案,在过滤歌曲的同时保持它返回的数据结构完好无损。
#### 到目前为止,我尝试了一些解决方案:
我可以在python中手动执行,只需让查询返回原始列表:
artists = Artist.query.all()
for artist in artists:
for song in artist.songs
if song == "search": # or starts with, or something else
# this is a song we want to match
我可以从中构建一个json响应,但这感觉就像我在使用sql,就像一个列表,而不是一个查询语言——没有充分利用它的潜力,牺牲了速度。
我可以查询艺术家表并按歌曲筛选:
q = Artist.query
q = q.join(Artist.songs)
q = q.filter(Song.name.like("%" + search + "%"))
q is a query which will return a list of artists
each artist has the aforementioned backref for a list of song
这将搜索,但返回每个结果的整个艺术家。例如,在此数据集中:
{artist1: [song1, song2, song3], artist2: [song4, song5, song6]}
寻找 `"song1"` 将返回artist1,backref将包含artist1的所有歌曲。我构造的json应该是 `{artist1: [song1, song2, song3]}` 而不是 `{artist1: song1}` ,这将是理想的。
我不确定是否有改进的方法来过滤掉我不想要的歌曲,或者是否查询艺术家表是错误的方法。
我探索过的另一种方法是对歌曲列表进行查询:
q = Song.query
q = q.join(Artist)
q = q.filter(Song.name.like("%" + i + "%"))
但是,在本例中,q.all()是一个歌曲列表,尽管它们包含艺术家名称,但它们并不是按艺术家名称“分组”的(我必须手动为每个艺术家制作一个具有相同艺术家名称的所有歌曲的列表)。i、 e.我能做的就是:
[song1, song2, song3, song4]
或者,
artists = {}
for song in songs:
artists[song.artist.name].append(song.name)
# or initialize artists[song.artist.name] = [song.name,]
我尝试过的所有这些解决方案似乎都涉及到python程序中的某种手动任务,我觉得应该有一种方法来改进我的解决方案,使其更加依赖sql。有没有办法查询表和返回组,按多对一关系的“一”部分分组/列出,只匹配符合特定条件的“多”?
暂无答案!
目前还没有任何答案,快来回答吧!