Sqlalchemy двойная таблица ассоциаций? - PullRequest
1 голос
/ 30 сентября 2019

Я хотел бы создать связь между объектом Dataset и всеми объектами Category через таблицу аннотаций.

Набор данных содержит коллекцию аннотаций. Каждая аннотация имеет одну категорию. Я хочу, чтобы Dataset.categories содержал уникальный набор категорий, состоящий из всех категорий всех аннотаций в этом экземпляре набора данных. Я пытался сделать это с двойной таблицей ассоциации (dataset_categories), но это не работает. Как правильно это сделать? Вот мой код:

Base = declarative_base()

dataset_categories = Table('dataset_categories', Base.metadata,
    Column('dataset_id', Integer, ForeignKey('datasets.id')),
    Column('annotation_id', Integer, ForeignKey('annotations.id')),
    Column('category_id', Integer, ForeignKey('categories.id')))

class Dataset(Base):
    __tablename__ = 'datasets'

    id = Column(Integer, primary_key=True)
    annotations = relationship("Annotation")
    categories = relationship("Category", secondary=dataset_categories)

class Annotation(Base):
    __tablename__ = 'annotations'
    id = Column(Integer, primary_key=True)
    category_id = Column(Integer, ForeignKey('categories.id'), nullable=False)
    category = relationship("Category")
    dataset_id = Column(Integer, ForeignKey('datasets.id'))

class Category(Base):
    __tablename__ = 'categories'
    id = Column(Integer, primary_key=True)
    name = Column(String, nullable=False, unique=True)
    dataset = relationship("Dataset", secondary=dataset_categories)
    dataset_id = Column(Integer, ForeignKey('datasets.id'),
                        back_populates='categories')

1 Ответ

1 голос
/ 01 октября 2019

Без требования, чтобы ассоциация содержала только уникальные категории, это было бы так же просто, как использовать association_proxy. Одним из вариантов является определение класса коллекции, который будет использоваться как set при определении отношения:

class Dataset(Base):
    __tablename__ = 'datasets'

    id = Column(Integer, primary_key=True)
    annotations = relationship("Annotation")
    categories = relationship("Category", secondary="annotations", collection_class=set)

С другой стороны, вторичная таблица relationship не обязательно должна быть базовой таблицей, ипоэтому можно использовать простой выбор из аннотаций:

class Dataset(Base):
    __tablename__ = 'datasets'

    id = Column(Integer, primary_key=True)
    annotations = relationship("Annotation")
    categories = relationship("Category",
                              secondary="""select([annotations.c.dataset_id,
                                                   annotations.c.category_id]).\\
                                           distinct().\\
                                           alias()""",
                              viewonly=True)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...