2011-02-01 25 views
5

Böyle bir Django veri modelini (veri alanları atlanmıştır) vardır: o Transition.objects.filter(...) sorgulamak için en kolay bu yüzden, ben sorgulandığındaDjango iç içe Sorgu kümelerini

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

, alanlar ya modelde olabilir kısıtlanmaya Diğer modellerde tüm alanlara yabancı anahtarlar aracılığıyla ulaşılabilir. Sonuç olarak ortaya çıkan QuerySet t'u arayın.

Şimdi ne ek olarak ilgilerini a = t.values('atom').distinct() gibi yapılabilir t tekabül Atom modeli, bir QuerySet a olduğunu. Çok uzak çok iyi.

Ancak, ben de upstate birini birinden bu Atom, hala orijinal seçimi t kriterler yansıtan devletler için Sorgu Kümesi tutan tek nitelik/alanını olması a girişlerin her istiyoruz veya lostate ForeignKeys.

Ben t üzerinde döngü çiftleri dışarı atma ve sonra bu liste ile Devletlere sorgulamak için bir Python set() için values('upstate_id') ve values('lostate_id') ekleyerek şu ana kadar Devletlerin benim Sorgu Kümesi oluşturduk. Ama sonra Atomlar içindeki devletlerin iç içe geçmiş yapısını elde edemiyorum.

Bunu yapma hakkında herhangi bir öneri, eğer bir şablona değil, bir çok üreticiye (yield deyim) geçiş yapmadığım için, büyük olasılıkla çok miktarda veriyi yayınlamanın güzel bir yolu olan, derecelendirilmemiş QuerySet s ile mümkündür.

cevap

2

Aşağıdaki işlev, yukarıda açıkladığım şeyi kullanır, ancak orijinal QuerySet'in atomla daha fazla filtrelenmesiyle döngü doğru bir yaklaşım olup olmadığından emin değilim. Orada bunun için akıllı bir çözüm olabilir ve mutlaka ilgi duyarım, bir kez daha

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

Ama:

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 

Şimdi ben böyle ihtiyacım iç içe döngü yapabilirsiniz.

0

set s anlayışına sahip olmanız çok güzel. Ancak, SQL'in In kullanılması verilerinizi çoğaltmayacaktır. Bunu bir an için düşünelim. "Bana bu listedeki bir atomu verin: (1, 2, 3, 3, 3, 4)", veritabanı 1, 2, 3 ve 4 atomlarını döndürecektir. Basitleştirmek için Python'a, veritabanı düzgün çalışabilmesi için set aritmetik işlemlerini yapmasını isteyin. set'u kullanma zamanları vardır, ancak senaryonuz bunlardan biri gibi görünmüyor. sizin için

Alternatif: modeliniz bazı değişiklikler varmış gibi

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

Buna rağmen, öyle görünüyor ki, ama tam olarak neyi başarmaya çalıştığımız şeyi anlamıyorum. Benim alternatifimde, atomlarla hiçbir şey yapmadığımı fark ettim. Bir OR işlemi gerçekleştirmek için Q nesnesini kullanıyorum, ancak yüksek veya düşük olup olmadığını belirtmek için Durum modeline bir bayrak ekleyebiliyor olabilirsiniz. Ya da bir tablo ile bir M2M ilişkisi kullanabilirsiniz. Ve sizin geçişiniz ve devletiniz neden bir atomla ilişkilendirilmeli?Sadece Transition den atom ortadan kaldırmak ve böylece gibi State den atom alabilir:

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) 
) 
İlgili konular