Avoiding n+1 queries to query model plus all ForeignKey associations?

放肆的年华 提交于 2019-12-07 19:26:08

问题


I have two models: call them questions and answers:

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)

I'd like to present all the questions and answers in one list, with the questions and answers ordered per my choosing:

Q1
  A1
  A2
  A3
Q2
  A10
  A9
  A4

Without creating n+1 database queries or creating silly looking templates. That's an easy join for a database guy like myself, but Toto informs us we're not in SQL land anymore:

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;

What's the best way in Django, and what would the template look like?

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

I see an older module that's a bit on track at django-batch-select. There's also select_related() which feels like it must be the answer, but if so the documentation is not quite making that clear.


回答1:


You can use FacetQuestion.objects.select_related('facetanswer_set').all()

Also have a look at setdefault(). It's a Python command that lets you build a nested dict structure. You query all questions and all answers and then build the structure you need in Python.




回答2:


There is an excellent guide here:

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

that describes exactly how to solve this problem.

Another approach is to use:

Django-selectreverse

which is a generic approach to utilizing what was described in the guide above.




回答3:


I can only answer you one part of the question.

select_related() is probably not what you are looking for. It will select you the "1-side" of a 1:n relationship. This would allow you to select all answers nd also fetch the related question for each answer in one go.

However, you can filter the query using properties of the related entity like this:

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

Still, your QuerySet will be based on the Answer-Model, so you can only iterate for a in answers.




回答4:


Based on searching other stack exchange answers: for dealing with the hierarchical data, the best seems to be http://django-mptt.github.com/django-mptt/

For simply reducing the number of queries select_related() is a great help.

For displaying the hierarchical result I have not yet found much.



来源:https://stackoverflow.com/questions/9442553/avoiding-n1-queries-to-query-model-plus-all-foreignkey-associations

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!