避免n + 1查询查询模型加上所有ForeignKey关联?

时间:2012-02-25 08:30:22

标签: django django-queryset

我有两种模式:称呼问题和答案:

class FacetQuestion(models.Model):
    the_question    = models.CharField(max_length=50)

class FacetAnswer(models.Model):
    question        = models.ForeignKey(FacetQuestion)
    display_order   = models.SmallIntegerField()
    the_answer      = models.CharField(max_length=1024)

我想在一个列表中提出所有问题和答案,并根据我的选择订购问题和答案:

Q1
  A1
  A2
  A3
Q2
  A10
  A9
  A4

不创建n + 1个数据库查询或创建看起来很模糊的模板。 对于像我这样的数据库人来说,这是一个简单的连接,但是Toto告诉我们我们不再是SQL领域了:

select title_short,answer_note from coat_facetquestion
join coat_facetanswer on (coat_facetanswer.question_id=coat_facetquestion.id)
order by coat_facetquestion.id,coat_facetanswer.display_order;

Django中最好的方法是什么,模板看起来像什么?

<ul>
    {% for q in questions %}
    <li>{{ q.the_question }}</li>
        {% for a in q.FacetAnswers_set.all %}
            <li>{{ q.the_answer }}</li>
        {% endfor %}
    {% endfor %}
</ul>

我看到一个较旧的模块在django-batch-select处有点正常。还有 select_related(),感觉它必须是答案,但如果是这样,那么文档就不那么明确了。

4 个答案:

答案 0 :(得分:1)

您可以使用FacetQuestion.objects.select_related('facetanswer_set').all()

另请查看setdefault()。这是一个Python命令,可以让你构建一个嵌套的dict结构。您查询所有问题和所有答案,然后在Python中构建所需的结构。

答案 1 :(得分:1)

这里有一个很好的指南:

http://blog.roseman.org.uk/2010/01/11/django-patterns-part-2-efficient-reverse-lookups/

它描述了如何解决这个问题。

另一种方法是使用:

Django-selectreverse

这是利用上述指南中描述的一般方法。

答案 2 :(得分:0)

我只能回答你问题的一部分。

select_related()可能不是你想要的。它会选择1:n关系的“1面”。这将允许您选择所有答案,并且还可以一次性获取每个答案的相关问题。

但是,您可以使用相关实体的属性过滤查询,如下所示:

FacetAnswer.objects.filter( question__property = 'some_value' ).select_related()

但是,您的QuerySet将基于答案模型,因此您只能迭代for a in answers

答案 3 :(得分:0)

基于搜索其他堆栈交换答案:为了处理分层数据,最佳似乎是http://django-mptt.github.com/django-mptt/

简单地减少查询次数 select_related()是一个很好的帮助。

为了显示分层结果,我还没有找到多少。