У меня возникли некоторые проблемы с использованием SQLAlchemy в полной мере в приложении Python, использующем Flask, и в понимании того, как работают отношения «один к одному» и как их можно использовать.
I 'я работаю с базой данных песен и исполнителей со схемой, которая выглядит следующим образом:
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)
);
Или, через Python SQLAlchemy, это выглядит так:
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]}
.(Конечная цель - вернуть это в разбивке на страницы в формате AJAX через Flask).
По сути, я надеюсь, что у меня будет голос артистов, который содержит список песен;и если бы я запустил поиск по определенной песне, он бы возвратил диктат той же структуры с только совпадающими песнями.
Если я хочу выполнить запрос и выбрать все песни из всехисполнителей, я могу просто запросить всех исполнителей и затем использовать атрибут 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 как список, а не язык запросов - не использую его в полной мере и жертвуяspeed.
Я мог бы запросить таблицу исполнителей и отфильтровать по песне:
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, а обратная ссылка будет содержать все песни для Artist1.Json, который я создаю, будет {artist1: [song1, song2, song3]}
, а не {artist1: song1}
, что было бы идеально.
Я не уверен, есть ли способ улучшить это, чтобы отфильтровать песни, которые я не хочу, или если запрос таблицы исполнителей - неправильный путь.
Другой метод, который я исследовал, это выполнение запроса в списке песен:
q = Song.query
q = q.join(Artist)
q = q.filter(Song.name.like("%" + i + "%"))
Однако, в этом случае q.all () - это список песен, ихотя они содержат имя исполнителя, они не «группируются» по имени исполнителя (мне пришлось бы выполнять ручную работу, чтобы составить список всех песен с одинаковым именем исполнителя для каждого исполнителя).то есть лучшее, что я мог сделать, это:
[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. Есть ли способ запросить таблицу и вернуть группы, сгруппированные / перечисленные по «одной» части отношения «многие к одному», только соответствующие «многим», которые соответствуют определенным критериям?