#python #sqlalchemy
#python #sqlalchemy
Вопрос:
У меня есть таблица ассоциаций фильмов и категорий, которые принадлежат этим фильмам, и я хочу получить все общие категории между двумя фильмами (просто нужен идентификатор категории).
Итак, если оба фильма имеют категорию «Триллер» с идентификатором category_id равным 5, я хочу получить 5. И если у них нет общих категорий, он просто возвращает None.
Таблица выглядит так:
class MovieCategoryScores(db.Model):
movie_id = db.Column(db.Integer, db.ForeignKey('movie.id'), primary_key=True)
category_id = db.Column(db.Integer, db.ForeignKey('category.id'), primary_key=True)
score = db.Column(db.Integer)
votes = db.Column(db.Integer)
category = relationship("Category", back_populates="movies")
movie = relationship("Movie", back_populates="categories")
Я знаю, что могу задавать вопросы
categories = MovieCategoryScores.query.filter(MovieCategoryScores.movie_id.in_([movie1, movie2])).all()
чтобы получить ВСЕ категории, и я попытался ввести (MovieCategoryScores.category_id)
после запроса только идентификаторы, но это не сработало, и я просто получил TypeError: 'BaseQuery' object is not callable
сообщение об ошибке.
Если бы я понял, как просто получить идентификаторы, я мог бы использовать что-то вроде:
categories.sort()
for index, category_id in enumerate(categories.copy()):
if categories[index 1] != category_id:
categories[index].remove()
return categories
Чтобы получить список только идентификаторов, из которых есть 2, но кажется, что должен быть какой-то лучший способ получить идентификаторы элементов, где оба имеют одинаковый category_id, просто с помощью команды запроса?
Любое решение будет высоко оценено!
Комментарии:
1. Используя мою собственную базу данных SQLAlchemy-SQLite3
2. вы видели мой ответ с distinct? Дает ли это желаемые результаты?
3. Я пытался понять, как его использовать, поскольку он делает прямо противоположное тому, что я хочу, верно? Это дает вам только идентификаторы, которые есть у одного из них, в то время как мне нужны идентификаторы, которые есть у них обоих? Или я неправильно понял, что он сделал?
4. А, понятно. Я пересмотрел свой ответ, чтобы получить желаемый результат.
Ответ №1:
Вы можете использовать having
и func.count() > 1
для получения противоположности distinct
( group_by
требуется для having
).
from sqlalchemy import func
categories = MovieCategoryScores.query.with_entities(MovieCategoryScores.category_id).filter(MovieCategoryScores.movie_id.in_([movie1, movie2])).group_by(MovieCategoryScores.category_id).having(func.count(MovieCategoryScores.category_id) > 1).all()
Или, если вы хотите получить Category.name
, вы можете выполнить следующее:
from sqlalchemy import func
categories = MovieCategoryScores.query.with_entities(MovieCategoryScores.name).filter(MovieCategoryScores.movie_id.in_([movie1, movie2])).group_by(MovieCategoryScores.category).having(func.count(MovieCategoryScores.category) > 1).all()
Комментарии:
1. Ах, ничего себе, это именно то, что я искал, большое вам спасибо! Теперь я тоже начинаю понимать общие черты с обычным SQL, спасибо!
2. Однако при замене .with_entities на MovieCategoryScores.category, чтобы попытаться получить объект категории, я получаю только массив кортежей, содержащих либо «True», либо «False», есть идеи, почему это может быть? Или, скорее, есть ли какой-либо способ обойти это, который не просто сначала получает все это, а затем получает категории?
3. Смотрите мое изменение, как получить имя категории. Если вы удалите
.name
, вы должны получить объект.4. О, я ссылался на то, как я хотел, чтобы объект category был ссылкой в таблице ассоциаций (category = relationship («Категория», back_populates =»фильмы»)), но после некоторых исследований я не думаю, что это возможно, поэтому я нашел собственное решение, большое спасибо за помощь!
Ответ №2:
Итак, после множества головных болей я придумал вот что:
def get_common_categories(movie1, movie2):
categories = MovieCategoryScores.query.with_entities(MovieCategoryScores.category_id).filter(MovieCategoryScores.movie_id.in_([movie1, movie2])).all()
categories.sort()
common = []
for index, category in enumerate(categories):
if index 1 < len(categories) and categories[index 1] == category:
common.append(category[0])
return common
Кажется глупым и как будто должен быть какой-то способ сделать это только с помощью запроса и фильтра, но я не смог понять это, так что пока придется обойтись этим.