2011-02-01 169 views
5

我有這樣(數據字段中省略)一個Django數據模型:Django的嵌套查詢集

class Atom(Model): 
    pass 

class State(Model): 
    atom = ForeignKey(Atom) 

class Transition(Model): 
    atom = ForeignKey(Atom) 
    upstate = ForeignKey(State,related_name='uptrans') 
    lostate = ForeignKey(State,related_name='lotrans') 

當我查詢時,字段被限制可以是在任一模式,所以它是最簡單的上Transition.objects.filter(...)查詢因爲其他模型中的所有字段都可以通過外鍵到達。我們調用生成的QuerySet t

現在我想要的另外是對應於t的Atom模型的QuerySet a,它可以像a = t.values('atom').distinct()一樣完成。到現在爲止還挺好。

不過,我也希望每個在a條目有一個屬性/字段保存查詢集爲這個原子,仍然反映原選區t標準的國家,通過upstate中的任一或lostate ForeignKeys。

我創建了我對國家的QuerySet到現在通過遍歷t,加入values('upstate_id')values('lostate_id')給一個Python set()扔了重複,然後用這個列表查詢國家。但是,我無法在原子範圍內實現國家的嵌套結構。

關於如何做到這一點的任何建議,歡迎,如有可能,未計算QuerySet S,因爲我通過他們不要爲模板,但一臺發電機(yield語句),這是流大量數據的一個很好的方式。

回答

2

我認爲下面的函數做了我上面描述的內容,但我不確定用原子進一步過濾原始QuerySet的循環是否是正確的方法。

def getAtomsWithStates(t): 
    atom_ids = set(t.values_list('atom_id',flat=True)) 
    atoms = Atoms.objects.filter(pk__in=atom_ids) 
    for atom in atoms: 
     upstate_ids = t.filter(atom=atom).values_list('upstate_id',flat=True) 
     lostate_ids = t.filter(atom=atom).values_list('lostate_id',flat=True) 
     all_ids = set(upstate_ids + lostate_ids) 

     # attach the new QuerySet to the entry in the outer one: 
     atom.States = State.objects.filter(pk__in=all_ids) 

    return atoms 

現在我能做的嵌套循環,我需要這樣的:

someAtoms = getAtomsWithStates(Transition.objects.filter(...)) 
for atom in someAtoms: 
    for state in atom.States: 
     print state.field 

但是,再次,有可能是這一個更聰明的解決方案,我想肯定是有興趣的。

0

你很瞭解set s。但是,使用SQL的In將不會複製您的數據。讓我們暫時考慮一下。如果我說:「給我一個在這個列表中的原子:(1,2,3,4,3,4)」,數據庫將返回原子1,2,3和4.爲了簡化,我不會請求Python執行set算術,因爲數據庫應該能夠很好地處理它。有時候可以使用set,但是你的場景看起來不像其中之一。

的爲您的選擇:

states = State.objects.filter(
    Q(pk__in=t.values_list('upstate', flat=True)) | 
    Q(pk__in=t.values_list('lostate', flat=True) 
) 

即使如此,好像你的模型可以使用一些變化,但我不完全理解你要完成的任務。請注意,在我的選擇中,我沒有對原子做任何事情。我使用Q對象來執行OR操作,但您可能可以將狀態標誌添加到狀態模型以指示它是高還是低。或者您可以使用與直通表的M2M關係。爲什麼你的過渡和你的狀態都與一個原子有關?你可以只消除Transition​​從State得到​​像這樣:

atoms = Atom.objects.filter(
    pk__in=State.objects.filter(
     Q(pk__in=t.values_list('upstate', flat=True)) | 
     Q(pk__in=t.values_list('lostate', flat=True) 
    ).values_list('atom', flat=True) 
)