SQLAlchemy запрашивает общие атрибуты?

#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
 

Кажется глупым и как будто должен быть какой-то способ сделать это только с помощью запроса и фильтра, но я не смог понять это, так что пока придется обойтись этим.