这是架构:
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
修改
它生成的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
答案 0 :(得分:2)
而不是column_property()
,您需要relationship()
with a composite "secondary"。列属性可以方便地将某些(标量)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
在名称中包含尾随空格。