2014-05-06 102 views
6

說我有一對夫婦的對象,有一個一對多的關係,就像過濾SQLAlchemy的查詢結果對象的一個​​一對多的屬性

class Parent(): 
    //id, other cols, etc 
    children = relationship("Child", backref="parent") 

class Child(): 
    parent_id = Column(Integer, ForeignKey("parent.id") 
    child_type = Column(Enum("a","b")) 

東西現在,我要查詢的父對象,但有他們的孩子通過child_type過濾,即類似

session.query(Parent).join(Parent.children).filter(Child.child_type == "a") 

這只是返回所有孩子的父,基本上忽視過濾器。這個結果是否可能?還是我還必須查詢Child?

回答

0

您試圖在一個查詢中得到兩個答案。要麼你可以要求所有父母都有一個孩子,或者你可以要求所有的孩子。在第一種情況下,如果您想要相應的孩子,您必須再次過濾孩子,在第二種情況下,您可以簡單地獲得相應的父母。但是,哪一種方法是正確的,取決於進一步的問題,你試圖解決。

6

確實,您的查詢添加了一個連接和一個篩選器,但只返回Parent實例。實際上,只有那些Parent實例至少有一個Child類型a
然後當您在這些父母的每個父母上訪問.children時,將會發出一條新的SQL語句,並且該父母的子女將被加載全部。您可以在內存中再次應用過濾器,或者創建自己的查詢,而不是靠關係導航(註釋)如下:

# select *only* those parents who have at least one child of type "a" 
parents = session.query(Parent).join(Parent.children).filter(Child.child_type == "a") 
for p in parents: 
    # 1. in-memory filter: now select only type "a" children for each parent 
    children_a = [c for c in p.children if c.child_type == 'a'] 
    # 2. custom query: now select only type "a" children for each parent 
    # children_a = session.query(Child).with_parent(p).filter(Child.child_type == "a") 

    print("AAA", p) 
    for c in children_a: 
     print("AAA ..", c) 

做在一個查詢的一種方法如下所示,但要小心因爲你正在有效地告訴sqlalchemy你爲父母加載全部孩子。您可以將此方法用於執行查詢的場景,然後丟棄/回收會話:

# select all parents, and eager-load children of type "a" 
parents = (session.query(Parent) 
     .join(Parent.children).filter(Child.child_type == "a") 
     # make SA think we loaded all *parent.children* collection 
     .options(contains_eager('children')) 
     ) 

for p in parents: 
    children_a = p.children # now *children* are *incorrectly* filtered 
    print("BBB", p) 
    for c in children_a: 
     print("BBB ..", c) 
相關問題