【问题标题】:How to return the count of related entities in sqlalchemy query如何在 sqlalchemy 查询中返回相关实体的计数
【发布时间】:2010-01-23 22:50:03
【问题描述】:

我是 sqlalchemy 的新手,虽然文档看起来相当详尽,但我找不到完全符合我要求的方法。

假设我有两个表:论坛和帖子。每个论坛都有一个父论坛和任意数量的帖子。我想要的是:

  • 顶级论坛列表
  • 可通过顶级论坛访问的热切加载的子论坛
  • 每个论坛的帖子计数

所以我开始了:

 query(Forum).filter(Forum.parent==None).all()

这为我提供了所有顶级论坛。当然访问子论坛会产生 n 个选择查询。

 query(Forum).options(eagerload('children')).filter(Forum.parent==None).all()

这解决了 n 选择问题。

现在我最好的猜测是这样的:

 query(Forum, func.count(Forum.children.posts)).options(eagerload('children')).filter(Forum.parent==None).group_by(Forum.children.id).all()

但我得到的只是:

AttributeError: Neither 'InstrumentedAttribute' object nor 'Comparator' object has an attribute 'posts'

我尝试了一些变体,但没有进一步的尝试。为了清楚起见,我正在寻找这个 SQL 的等价物:

select Forum.*, Child.*, count(Post.id)
from Forum
left join Forum Child on Child.parent = Forum.id
left join Message on Message.forum = Child.id
where Forum.parent is null
group by Child.id

【问题讨论】:

    标签: python sql sqlalchemy


    【解决方案1】:

    因为您希望在子论坛对象上可以访问帖子计数,所以您需要在设置映射器时将其声明为列属性。列属性声明应如下所示(假设您使用声明性):

    Forum.post_count = column_property(select([func.count()],
            Message.__table__.c.forum == Forum.__table__.c.id
        ).correlate(Forum.__table__).as_scalar().label('post_count'),
        deferred=True)
    

    然后你可以这样表达你的查询:

    query(Forum).filter_by(parent=None).options(
        eagerload('children'),
        undefer('children.post_count'))
    

    另一种选择是分别选择子项和计数。在这种情况下,您需要自己进行结果分组:

    ChildForum = aliased(Forum)
    q = (query(Forum, ChildForum, func.count(Message.id))
            .filter(Forum.parent == None)
            .outerjoin((ChildForum, Forum.children))
            .outerjoin(ChildForum.posts)
            .group_by(Forum, ChildForum)
        )
    
    from itertools import groupby
    from operator import attrgetter
    
    for forum, childforums in groupby(q, key=attrgetter('Node')):
        for _, child, post_count in childforums:
            if child is None:
                # No children
                break
            # do something with child
    

    【讨论】:

    猜你喜欢
    • 2012-12-18
    • 1970-01-01
    • 1970-01-01
    • 2019-06-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多