如何将带有 WHERE 子句的 SQL 作为子查询转换为 SQLAlchemy
How to convert SQL with WHERE clause as subquery to SQLAlchemy
class Post(Base):
__tablename__ = "posts"
id = Column(Integer, primary_key=True, index=True)
title = Column(String(50))
posts_to_tags = relationship(
"PostsToTags", back_populates="post", cascade="all,delete")
class Tag(Base):
__tablename__ = "tags"
id = Column(Integer, primary_key=True, index=True)
tag = Column((String(50)), index=True)
posts_to_tags = relationship(
"PostsToTags", back_populates="tag", cascade="all,delete")
class PostsToTags(Base):
__tablename__ = "posts_to_tags"
id = Column(Integer, primary_key=True, index=True)
post_id = Column(Integer, ForeignKey(
"posts.id", ondelete="CASCADE"), index=True)
post = relationship("Post", back_populates="posts_to_tags")
tag_id = Column(Integer, ForeignKey(
"tags.id", ondelete="CASCADE"), index=True)
tag = relationship("Tag", back_populates="posts_to_tags")
我的尝试:
q = session.query(Post)
if tags:
tag_id_list = []
for tag in tags:
tag = session.query(Tag).filter(Tag.tag == tag).first()
tag_id_list.append(tag.id)
q = q.join(PostsToTags, Post.id == PostsToTags.post_id)
q = q.filter(PostsToTags.tag_id.in_(tag_id_list))
我需要在 python 中创建一个空数组来存储 tag_id_list
。我知道这不是最好的,因为在 MYSQL 中。很清楚:
SELECT DISTINCT p.id, p.title, p.body, p.created_at
FROM posts p INNER JOIN posts_to_tags ptt ON p.id = ptt.post_id
WHERE
(
SELECT t.tag
FROM tags t
WHERE t.id = ptt.tag_id
)
IN ("animal", "people")
而且我在 SQL 查询中无法理解。有些帖子有两个标签:("animal", "people")
但是在我的代码中。没有重复!:
例如:
- 约翰 - #people
- 彼得 - #people
- 狗 - #animal
- 猫 - #animal
- John Tiger - #people #animal
然后用我的代码 Python:
tags = ["people", "animal"] ->result: John, Peter, Dog, Cat, John Tiger
并使用 SQL 查询:
tags = ["people", "animal"] ->result: John, Peter, Dog, Cat, John Tiger, John Tiger
所以“John Tiger”重复了。
所以我的问题是:
- 不同结果的原因是什么
- 编写 SQLAlchemy 的最佳方法,无需创建空数组。我尝试了子查询之类的东西,但是由于理解错误,我无法编写出没有错误的好代码。
您已经完成了设置 ORM 的艰苦工作,好好利用它吧。
类似这样的内容应该能让您获得正确的帖子:
tags = ["people", "animal"]
q = (
session.query(Post)
.where(
Post.posts_to_tags.any(
PostToTags.tag.has(
Tag.tag.in_(tags)
)
)
)
)
另见。您的 PostToTags
table 可以设为不可见,这样您就可以直接访问 Post.tags
作为关系。
class Post(Base):
__tablename__ = "posts"
id = Column(Integer, primary_key=True, index=True)
title = Column(String(50))
posts_to_tags = relationship(
"PostsToTags", back_populates="post", cascade="all,delete")
class Tag(Base):
__tablename__ = "tags"
id = Column(Integer, primary_key=True, index=True)
tag = Column((String(50)), index=True)
posts_to_tags = relationship(
"PostsToTags", back_populates="tag", cascade="all,delete")
class PostsToTags(Base):
__tablename__ = "posts_to_tags"
id = Column(Integer, primary_key=True, index=True)
post_id = Column(Integer, ForeignKey(
"posts.id", ondelete="CASCADE"), index=True)
post = relationship("Post", back_populates="posts_to_tags")
tag_id = Column(Integer, ForeignKey(
"tags.id", ondelete="CASCADE"), index=True)
tag = relationship("Tag", back_populates="posts_to_tags")
我的尝试:
q = session.query(Post)
if tags:
tag_id_list = []
for tag in tags:
tag = session.query(Tag).filter(Tag.tag == tag).first()
tag_id_list.append(tag.id)
q = q.join(PostsToTags, Post.id == PostsToTags.post_id)
q = q.filter(PostsToTags.tag_id.in_(tag_id_list))
我需要在 python 中创建一个空数组来存储 tag_id_list
。我知道这不是最好的,因为在 MYSQL 中。很清楚:
SELECT DISTINCT p.id, p.title, p.body, p.created_at
FROM posts p INNER JOIN posts_to_tags ptt ON p.id = ptt.post_id
WHERE
(
SELECT t.tag
FROM tags t
WHERE t.id = ptt.tag_id
)
IN ("animal", "people")
而且我在 SQL 查询中无法理解。有些帖子有两个标签:("animal", "people")
但是在我的代码中。没有重复!:
例如:
- 约翰 - #people
- 彼得 - #people
- 狗 - #animal
- 猫 - #animal
- John Tiger - #people #animal
然后用我的代码 Python:
tags = ["people", "animal"] ->result: John, Peter, Dog, Cat, John Tiger
并使用 SQL 查询:
tags = ["people", "animal"] ->result: John, Peter, Dog, Cat, John Tiger, John Tiger
所以“John Tiger”重复了。
所以我的问题是:
- 不同结果的原因是什么
- 编写 SQLAlchemy 的最佳方法,无需创建空数组。我尝试了子查询之类的东西,但是由于理解错误,我无法编写出没有错误的好代码。
您已经完成了设置 ORM 的艰苦工作,好好利用它吧。
类似这样的内容应该能让您获得正确的帖子:
tags = ["people", "animal"]
q = (
session.query(Post)
.where(
Post.posts_to_tags.any(
PostToTags.tag.has(
Tag.tag.in_(tags)
)
)
)
)
另见PostToTags
table 可以设为不可见,这样您就可以直接访问 Post.tags
作为关系。