Django嵌套QuerySet

时间:2011-02-01 12:56:06

标签: python django django-models django-queryset

我有一个像这样的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

现在我想要的是与a对应的Atom模型的QuerySet t,可以像a = t.values('atom').distinct()那样完成。到目前为止一切都很好。

但是,我还希望a中的每个条目都有一个属性/字段,其中包含此Atom状态的QuerySet,仍然反映原始选择的条件t,通过upstatelostate ForeignKeys中的任何一个。

到目前为止,我已经通过循环t在状态上创建了我的QuerySet,将values('upstate_id')values('lostate_id')添加到Python set()以丢弃重复项,然后用这个清单查询国家。但后来我无法在Atoms中实现状态的嵌套结构。

如果可能的话,对于未评估的QuerySet,我们欢迎任何有关如何执行此操作的建议,因为我将它们传递给模板而不是生成器(yield语句),这是一种很好的方法。流式传输大量数据。

2 个答案:

答案 0 :(得分: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

但是,再一次,可能会有一个更聪明的解决方案,我肯定会感兴趣。

答案 1 :(得分:0)

您对set s的理解非常好。但是,使用SQL的In不会复制您的数据。让我们考虑一下。如果我说,“给我一个在这个列表中的原子:(1,2,3,3,4,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操作,但您可以向State模型添加一个标志,以指示它是高还是低。或者您可以使用与通过表的M2M关系。为什么你的过渡和你的状态都与原子有关?您可以从atom中删除Transition并从atom获取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)
)