2010-01-23 58 views
10

我是sqlalchemy的新手,儘管文檔看起來相當透徹,但我找不到完全符合我需要的方式。如何返回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 

回答

8

因爲你想要的崗位數要對孩子論壇訪問的對象,您需要將其聲明爲列屬性設置的時映射器。列財產申報應該是這個樣子(假設你使用的聲明):

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