使用sqlalchemy仅从相关表中选择一行

shr*_*oud 5 python sqlalchemy

假设我有一个Author表和一个Post表,每个作者可以有几个帖子.

现在,通过单个 sqlalchemy查询,我想获得所有活跃的作者和每个最新发布的帖子.

我一直试图通过获取加载作者的帖子列表,使用子查询将结果组合在一起,如下所示:

subquery = DBSession.query(Author.id, func.max(Post.publish_date).label("publish_date")) \
    .join(Post.author) \
    .filter(Post.state == 'published') \
    .filter(Author.state == 'active') \
    .group_by(Author.id) \
    .subquery()

query = DBSession.query(Post) \
    .options(joinedload(Post.author)) \
    .join(Post.author) \
    .join(subquery, and_(Author.id == subquery.c.id, 
                         Post.publish_date == subquery.c.publish_date))
Run Code Online (Sandbox Code Playgroud)

但是,如果我有一个来自具有相同publish_date的作者的两个帖子,并且这些是最新的帖子,那意味着我将该作者在我的结果列表中出现两次.虽然我可以使用第二个子查询来消除欺骗(使用func.max(Post.id)),但这似乎真的是非常错误的方法.有没有更好的方法来解决这个问题?

(同样,我正在寻找一个单一的查询,所以我试图避免查询作者表,然后循环并对我的结果中的每个作者进行Post查询.)

van*_*van 8

我会这样做:

LastPost = aliased(Post, name='last')
last_id = (
    session.query(LastPost.id)
    .filter(LastPost.author_id == Author.id)
    .order_by(LastPost.publish_date.desc())
    .order_by(LastPost.id.desc())
    .limit(1)
    .correlate(Author)
    .as_scalar()
)

query = (
    DBSession.query(Author, Post)
    .outerjoin(Post, Post.id == last_id)
)

for author, last_post in query:
    print(author, last_post)
Run Code Online (Sandbox Code Playgroud)

如您所见,结果是tuple成对的(Author, LastPost).如果您只想要至少有一个作者,请
更改outerjoin为. 此外,我不会预先加载任何关系,以避免任何混淆.joinPost
Author.post