2010-01-23 14 views
10

Ben sqlalchemy için yeni konumdayım ve belgeler oldukça kapsamlı görünüyor, ne istediğimi yapmak için bir yol bulamadık.sqlalchemy sorgusunda ilgili varlıkların sayımı nasıl döndürülebilir

İki tabam var diyelim: forum ve posta. Her forumda bir ana forum ve herhangi bir sayıda yayın vardır. İstediğim geçerli:

  • üst düzey forumlar yoluyla üst düzey forumları listesi
  • Merakla yüklenen çocuk forumları erişilebilir
  • her çocuk için mesajların sayımı forumu

Ben de şu şekilde başladım:

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

Bu bana en üst seviyeyi verir forumları. Tabii ki çocuk forumlarına erişme, seçim sorguları verir.

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

Bu, n seçim sorununu çözer.

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

Ama olsun hepsi:

Şimdi benim en iyi tahmin şöyle gider

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

Birkaç varyasyonları denedim ama bundan başka herhangi yok. Sadece netlik için bu SQL eşdeğer arıyorum:

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 

cevap

8

kurarken sonrası sayımı bir sütun özelliği olarak ilan gerekir nesnelerin çocuk Forum erişilebilir olmak istiyorum haritacılar. Sütun özellik bildirimi bu gibi görünmelidir (eğer bildirim kullanmak varsayarak): O zaman ifade bu gibi sorgu yapabilirsiniz

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')) 

Diğer bir seçenek ayrı ayrı çocuk ve sayıları seçmek olacaktır . Bu durumda, kendiniz gruplama sonucunu yapmanız gerekir:

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