#python #database #sqlalchemy
#python #База данных #sqlalchemy
Вопрос:
Я пытаюсь создать таблицу в SQLAlchemy, которая соединяла бы фильм и категорию и присваивала бы ему оценку (у Shining в категории Thriller может быть оценка 700, В то время как у Shining в категории Drama может быть оценка 540 и т. Д.).
Это означает, что таблица будет содержать много ссылок на The Shining и много ссылок на Thriller, но только в одном случае, когда это комбинация The Shining и Thriller, которая также будет включать оценку 700. Эта картинка хорошо объясняет это.
Категория и фильм являются собственными классами.
Итак, в поисках ответа я обнаружил, что у меня может быть несколько первичных ключей, но в данном случае это не сработает, поскольку первичные ключи должны быть уникальными, а идентификатор фильма и идентификатор категории не являются уникальными.
Я нашел слово «Составной ключ», которое звучит так, как я ищу, но продемонстрировано в SQLAlchemy, похоже, оно не делает то же самое, что я думал.
Как мне создать таблицу, которая выполняет то, что я ищу? ОН ЖЕ «Оценки фильмов категории» с картинки? И причина, по которой я не просто создаю обычный идентификатор, который будет служить первичным ключом, заключается в том, что он никогда не будет использоваться, я только каждый раз запрашиваю эту таблицу с идентификаторами фильмов и категорий.
Заранее спасибо!
Ответ №1:
Это можно решить с помощью объекта ассоциации. Какое отношение «Многие ко многим» основано на объекте, чтобы иметь возможность хранить дополнительные данные.
class Association(Base):
__tablename__ = 'association'
movie_id = Column(Integer, ForeignKey('movie.id'), primary_key=True)
category_id = Column(Integer, ForeignKey('category.id'), primary_key=True)
score = Column(Integer)
votes = Column(Integer)
category = relationship("Category", back_populates="movies")
movie = relationship("Movie", back_populates="categories")
class Movie(Base):
__tablename__ = 'movie'
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(50))
categories = relationship("Association", back_populates="movie")
class Category(Base):
__tablename__ = 'category'
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(50))
movies = relationship("Association", back_populates="category")
Используйте sqlite_autoincrement=True
с sqlite для создания автоинкремента на уровне базы данных.
Прежде чем вы сможете добавить категорию к фильму, она должна быть связана с экземпляром ассоциации:
# create movie, append a category via association
m = Movie()
a = Association(score=700, votes=0)
a.category = Category()
m.categories.append(a)
# iterate through category objects via association, including association
# attributes
for assoc in m.categories:
print(assoc.score)
print(assoc.category)
Комментарии:
1. Спасибо, это очень помогает! Придется углубиться в ассоциативные объекты, чтобы понять, что происходит.
2. Хорошо, это, похоже, сработало, но теперь мне говорят:
Column 'association.category_id' is marked as a member of the primary key for table 'association', but has no Python-side or server-side default generator indicated, nor does it indicate 'autoincrement=True' or 'nullable=True', and no explicit value is passed. Primary key columns typically may not store NULL. Note that as of SQLAlchemy 1.1, 'autoincrement=True' must be indicated explicitly for composite (e.g. multicolumn) primary keys if AUTO_INCREMENT/SERIAL/IDENTITY behavior is expected for one of the columns in the primary key.
3. Хорошо, исправление заключалось в добавлении
a.movie = m
, поскольку, похоже, оно не получало фильм автоматически, когда к нему добавлялась ассоциация. Не уверен, почему: (4. @cobble, я изменил ответ, чтобы избавиться от предупреждения. Очень странно, что вам нужно установить
a.movie = m
, поскольку это должно обрабатыватьсяappend
в модели. Я протестировал его локально, и результаты соответствуют ожидаемым без его установки.5. Ах, хорошо, тогда я могу знать, почему это происходит. Я импортирую все данные из другой базы данных, что означает, что я устанавливаю идентификатор напрямую (поэтому автоинкремент ничего не делает). И мне тоже показалось странным, что мне нужно было его установить, поскольку мое понимание таблиц было таким же, как у вас, я продолжу играть с ним и посмотрю, получу ли я какие-либо другие результаты. Все равно спасибо!