【问题标题】:Django nested QuerySetsDjango 嵌套查询集
【发布时间】:2011-06-19 06:28:02
【问题描述】:

我有一个这样的 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模型的QuerySeta,可以像a = t.values('atom').distinct()一样完成。到目前为止一切顺利。

但是,我还希望a 中的每个条目都具有 一个 属性/字段,该属性/字段包含此 Atom 状态的 QuerySet,仍然反映原始选择 @987654328 的标准@,通过upstatelostate ForeignKeys 之一。

到目前为止,我已经通过循环 t,将 values('upstate_id')values('lostate_id') 添加到 Python set() 以丢弃重复项,然后使用此列表查询州来创建我的 QuerySet。但是我无法在 Atoms 中实现 State 的嵌套结构。

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

【问题讨论】:

    标签: python django django-models django-queryset


    【解决方案1】:

    我认为下面的函数做了我上面描述的事情,但我不确定通过 atom 进一步过滤原始 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
    

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

    【讨论】:

      【解决方案2】:

      很高兴你能了解sets。但是,使用 SQL 的 In 不会复制您的数据。让我们考虑一下。如果我说,“给我一个在这个列表中的原子:(1, 2, 3, 3, 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 操作,但您可以在 State 模型中添加一个标志来指示它是高还是低。或者,您可以将 M2M 关系与直通表一起使用。为什么你的转换和你的状态都与一个原子相关联?您可以从 Transition 中删除 atom 并从 State 中获取 atom,如下所示:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-11-29
        • 2013-11-12
        • 1970-01-01
        • 2014-10-08
        • 1970-01-01
        • 2016-01-31
        • 1970-01-01
        相关资源
        最近更新 更多