我有一个像这样的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
,通过upstate
或lostate
ForeignKeys中的任何一个。
到目前为止,我已经通过循环t
在状态上创建了我的QuerySet,将values('upstate_id')
和values('lostate_id')
添加到Python set()
以丢弃重复项,然后用这个清单查询国家。但后来我无法在Atoms中实现状态的嵌套结构。
如果可能的话,对于未评估的QuerySet
,我们欢迎任何有关如何执行此操作的建议,因为我将它们传递给模板而不是生成器(yield
语句),这是一种很好的方法。流式传输大量数据。
答案 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)
)