Django中的左外部反向select_related?

aug*_*men 28 django left-join django-queryset django-select-related

想象一下以下模型:

class Parent(Model):
    ...

class Child(Model)
    father = ForeignKey(Parent)
    ...
Run Code Online (Sandbox Code Playgroud)

有些父母有孩子,有些则没有孩子(他们不是真正意义上的父母,只是虚构的名字).

我想提出以下问题:我想列出所有的父母,如果他们有孩子,也请带孩子.这相当于Child表的左外连接,即:

select * from app_parent left join app_child on child_father_id=parent_id
Run Code Online (Sandbox Code Playgroud)

这样,当我在模板中调用Parent.child_set时,我不会在数据库中访问数十亿次.有没有办法做到这一点?谢谢

Gau*_*oun 22

从Django 1.4开始prefetch_related做你想要的.

Parent.objects.prefetch_related('child_set')
Run Code Online (Sandbox Code Playgroud)

相关(!)django docs:https://docs.djangoproject.com/en/dev/ref/models/querysets/#prefetch-related.

  • 我认为这与 OP 要求的不同。我刚刚运行了 select_prefetch,它实际上运行了 2 个查询: 1. select * from parents;2. select * from child where parent_id IN (-bunch-of-comma-separated-ids-from-query-1-go-here-) 这是它应该如何工作还是我做错了什么? (2认同)

Dan*_*man 13

很抱歉再次发布一个链接到我的博客,但我写了一个技术来模拟back_relations上的select_related.

  • +1,但这里的摘要也会有所帮助. (7认同)

aug*_*men 6

在这种情况下,我认为最好的办法是列出子项,然后从中获取父项,如下所示:

children = Child.objects.filter(...).select_related('parent').order_by('parent')
Run Code Online (Sandbox Code Playgroud)

然后在模板中,可能使用a regroup(注意order_by上面):

{% regroup children by parent as parents %}
<ul>
{% for parent in parents %}
    <li>{{ parent.grouper }}
    <ul>
    {% for child in parents.list %}
    ...
    {% endfor %}
    </ul>
    </li>
{% endfor %}
</ul>
Run Code Online (Sandbox Code Playgroud)