如何将带有 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")

但是在我的代码中。没有重复!:

例如:

然后用我的代码 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”重复了。

所以我的问题是:

您已经完成了设置 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 作为关系。