Django 嵌套查询集

发布于 2024-10-15 09:50:30 字数 1063 浏览 3 评论 0原文

我有一个像这样的 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(...)< 上查询是最简单的/code> 因为其他模型中的所有字段都可以通过外键访问。我们将生成的查询集称为 t

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

但是,我还希望 a 中的每个条目都有 一个 属性/字段,用于保存该 Atom 状态的查询集,仍然反映原始选择的标准t,通过 upstatelostate 外键之一。

到目前为止,我已经通过循环 t、添加 values('upstate_id')values('lostate_id') 在 State 上创建了查询集> 到 Python set() 以丢弃重复项,然后使用此列表查询 State。但这样我就无法实现原子内状态的嵌套结构。

如果可能的话,可以使用未评估的 QuerySet 来提供有关如何执行此操作的任何建议,因为我不是将它们传递到模板中,而是传递到生成器(yield 语句)中,这是一个传输大量数据的好方法。

I have a Django data model like this (data fields omitted):

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

When I query, the fields to be restricted can be in either model, so it is easiest to query on Transition.objects.filter(...) since all fields in the other models can be reached through the foreign keys. Let's call the resulting QuerySet t.

Now what I want in addition is a QuerySet a of the Atom model that corresponds to t, which can be done like a = t.values('atom').distinct(). So far so good.

However, I also want each of the entries in a to have one attribute/field that holds the QuerySet for the States of this Atom, still reflecting the criteria on the original selection t, through either one of the upstate or lostate ForeignKeys.

I have created my QuerySet on States up to now by looping over t, adding the values('upstate_id') and values('lostate_id') to a Python set() for throwing out duplicates, and then querying States with this list. But then I cannot achieve the nested structure of States within Atoms.

Any suggestions on how to do this are welcome, if possible with unevaluated QuerySets, since I pass them not into a template but a generator (yield statements), which is a nice way of streaming large amounts of data.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

笔芯 2024-10-22 09:50:30

我认为以下函数执行我上面描述的操作,但我不确定按原子进一步过滤原始 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

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

I think the following function does what I describe above, but I am not sure if the loop with further filtering of the original QuerySet by atom is the right approach.

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

Now I can do the nested loop that I need like this:

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

But, once again, there might be a smarter solution for this and I'd surely be interested.

柏拉图鍀咏恒 2024-10-22 09:50:30

很高兴您能够理解集合。但是,使用 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 运算,但您也许可以向状态模型添加一个标志来指示它是高还是低。或者您可以使用带有直通表的 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)
)

It is very nice that you have the understanding of sets. However, using SQL's In will not duplicate your data. Let's consider that for a moment. If I say, "Give me an atom that is in this list: (1, 2, 3, 3, 3, 4)," the database will return atoms 1, 2, 3, and 4. For simplification, I would not ask Python to perform the set arithmetic since the database should be able to handle it just fine. There are times to use set, but your scenario doesn't seem like one of them.

An alternative for you:

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

Even so, it seems like your model could use some changes, but I don't fully understand what you're trying to accomplish. Notice how that in my alternative, I don't do anything with atoms. I use the Q object to be able to perform an OR operation, but you might be able to add a flag to the State model to indicate if it is high or low. Or you could use an M2M relation with a through table. And why would your transition and your state both be associated with an atom? You could just eliminate atom from Transition and get the atom from State like so:

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)
)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文