Как объединить различные значения в объединенной таблице в SQLAlchemy? - PullRequest
0 голосов
/ 18 мая 2018

Вот схема:

post_tag = Table("post_tag", Base.metadata,
                 Column("post_id", Integer, ForeignKey("post.id")),
                 Column("tag_id ", Integer, ForeignKey("tag.id")))


class Post(Base):
    id = Column(Integer, primary_key=True)
    tags = relationship("Tag", secondary=post_tag, backref="post", cascade="all")
    collection_id = Column(Integer, ForeignKey("collection.id"))


class Tag(Base):
    id = Column(Integer, primary_key=True)
    description = Column("description", UnicodeText, nullable=False, default="")
    post_id = Column(Integer, ForeignKey("post.id"))


class Collection(Base):
    id = Column(Integer, primary_key=True)
    title = Column(Unicode(128), nullable=False) 
    posts = relationship("Post", backref="collection", cascade="all,delete-orphan")

    tags = column_property(select([Tag])
                           .where(and_(Post.collection_id == id, Tag.post_id == Post.id))
                           .correlate_except(Tag))

По сути, Post до Tag - это число ко многим, а от Collection до Post - одно ко многим.

Я хочу Collection.tags вернуть отдельный набор тегов сообщений в коллекции.

Однако при доступе к Collection.tags:

sqlalchemy я получаю следующую ошибку.exc.OperationalError: (sqlite3.OperationalError) разрешен только один результат для SELECT, являющегося частью выражения

EDIT

SQL, который он генерирует

SELECT (SELECT tag.id, tag.description, tag.post_id 
FROM tag, post 
WHERE post.collection_id = collection.id AND tag.post_id = post.id) AS anon_1, collection.id AS collection_id, collection.title AS collection_title 
FROM collection 
WHERE collection.id = 1

Я считаю, что post_id = Column(Integer, ForeignKey("post.id")) не так, как post_id в post_tag.Однако, если я изменю его на post_tag.post_id, он выдаст AttributeError: 'Table' object has no attribute 'post_id'

EDIT2

Я изменю его на

tags = column_property(select([Tag])
                       .where(and_(Post.collection_id == id, post_tag.c.post_id == Post.id,
                                   post_tag.c.tag_id == Tag.id)))

Хотя этоработает

SELECT tag.id, tag.description, tag.category_id, tag.post_id 
FROM tag, post, post_tag 
WHERE post.collection_id = 1 AND post_tag.post_id = post.id AND post_tag.tag_id = tag.id

, но запрос, генерируемый SQLAlchemy, не

SELECT (SELECT tag.id, tag.description, tag.category_id, tag.post_id 
FROM tag, post, post_tag 
WHERE post.collection_id = collection.id AND post_tag.post_id = post.id AND post_tag.tag_id = tag.id) AS anon_1
FROM collection 
WHERE collection.id = 1

1 Ответ

0 голосов
/ 18 мая 2018

Вместо column_property() вам нужен relationship() с составным «вторичным» .Свойство столбца удобно для отображения некоторого (скалярного) выражения SQL в виде «столбца», который загружается вместе с другими атрибутами.С другой стороны, вы, кажется, хотите отобразить коллекцию связанных Tag объектов:

class Collection(Base):
    id = Column(Integer, primary_key=True)
    title = Column(Unicode(128), nullable=False)
    posts = relationship("Post", backref="collection", cascade="all,delete-orphan")

    tags = relationship(
        "Tag", viewonly=True,
        primaryjoin="Collection.id == Post.collection_id",
        secondary="join(Post, post_tag)",
        secondaryjoin="Tag.id == post_tag.c.tag_id")

Если вы хотите загружать отношения, как в случае со свойством столбца, вы можете по умолчанию установитьlazy="join".Также возможно определить стратегию активной загрузки для каждого запроса, используя Query.options():

session.query(Collection).\
    options(joinedload(Collection.tags)).\
    all()

Обратите внимание, что в вашем примере в определении типа есть опечатка (?)дополнительный стол post_tags.Столбец tag_id содержит в конце пробельные символы.

...