遍历Django中的相关对象:遍历查询集或使用单行select_related(或prefetch_related) [英] Iterating over related objects in Django: loop over query set or use one-liner select_related (or prefetch_related)

查看:281
本文介绍了遍历Django中的相关对象:遍历查询集或使用单行select_related(或prefetch_related)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个新闻通讯应用程序,其中一个新闻通讯在每一期中都有多篇文章.我想在线显示一个摘要页面,其中列出了新闻通讯的年份,数量和标签,然后在无序列表中显示该期的所有文章.我对Django很陌生,所以我正在尝试确定执行此操作的最佳方法.

I have a newsletter application where a newsletter has multiple articles within each issue. I want to display a summary page online that lists the newsletter year, volume and label, and then in an unordered list display all the articles in the issue. I am quite new to Django so I am trying to determine the best way to do this.

我已经定义了模型(只是相关部分):

I have the models defined (just the relevant parts):

Models.py:

Models.py:

class Newsletter(models.Model):
    volume = models.ForeignKey(Volume)
    year   = models.IntegerField()
    season = models.CharField(max_length=6, choices=VOLUME_SEASON)
    label  = models.CharField(max_length=20)
    number = models.IntegerField()

class Article(models.Model):
    newsletter = models.ForeignKey(Newsletter)
    section    = models.ForeignKey(Section)
    title      = models.CharField(max_length=200)

我想在网络上看到的内容如下:

What I want to see on the web looks like:

<h2>Spring 2012</h2>
<p>Volume 14, Number 1</p>
<ul>
    <li>Foo</li>
    <li>Bar</li>
    <li>Baz</li>
</ul>

<h2>Winter 2011</h2>
<p>Volume 13, Number 4</p>
<ul>
  <li>Boffo</li>
</ul>

非常简单.但是,我对写我的观点的最好方法感到困惑.是否使用:

Pretty simple. However, I am confused by the best way to write my view. Whether to use:

  • 我先zip()然后在模板中进行迭代的两个列表
  • 使用select_related()查询集
  • 使用prefetch_related()查询集
  • Two lists which I zip() and then iterate over in the template
  • Use the select_related() queryset
  • Use the prefetch_related() queryset

我可以使用第一个选项来工作:

I have it working using the first option:

Views.py:

Views.py:

from django.shortcuts import render_to_response, get_object_or_404
from www.apps.newsletter.models import Newsletter, Article

def index(request):
    article_group = []
    newsletter = Newsletter.objects.all().order_by('-year', '-number')
    for n in newsletter:
        article_group.append(n.article_set.all())
    articles_per_newsletter = zip(newsletter, article_group)

    return render_to_response('newsletter/newsletter_list.html',
                              {'newsletter_list': articles_per_newsletter})

然后使用以下模板呈现它:

And then render it using the following template:

Newsletter_list.html:

Newsletter_list.html:

{% block content %}
  {% for newsletter, articles in newsletter_list %}
    <h2>{{ newsletter.label }}</h2>
    <p>Volume {{ newsletter.volume }}, Number {{ newsletter.number }}</p>
    <p>{{ newsletter.article }}</p>
    <ul>
    {% for a in articles %}
      <li>{{ a.title }}</li>
    {% endfor %}
    </ul>
  {% endfor %}
{% endblock %}

非常简单,但是由于我是Django的新手,我想知道我所做的事情是否在功能强大的ORM方面完全没有效率.我希望不必即时制作一个列表,然后如果有更快的方法,就可以将两个列表一起zip().

Pretty straightforward, but as I am pretty new to Django I was wondering if what I am doing is completely inefficient in terms of its powerful ORM. I would love to not have to make a list on-the-fly and then zip() the two lists together if there is a faster way.

TIA.

推荐答案

您现在正在执行的方法将大量低效,因为这将导致1 + N的查询数量.也就是说,对所有新闻通讯的查询为1,然后对这些n.article_set.all()结果的每次评估都为1.因此,如果在第一个查询中有100个Newletter对象,则将进行101个查询.

The approach you are doing now will be heavily inefficient, because it will result in an 1+N number of queries. That is, 1 for the query of all your Newsletters, and then 1 for every single time you evaluate those n.article_set.all() results. So if you have 100 Newletter objects in that first query, you will be doing 101 queries.

这是使用prefetch_related的绝佳理由.它只会导致2个查询.一个可以获取新闻通讯,一个可以批量获取相关文章.尽管您仍然完全可以继续执行zip来组织它们,但是它们已经被缓存了,因此实际上您可以将查询直接传递到模板并在其上循环. :

This is an excellent reason to use prefetch_related. It will only result in 2 queries. One to get the Newsletters, and 1 to batch get the related Articles. Though you are still perfectly able to keep doing the zip to organize them, they will already be cached, so really you can just pass the query directly to the template and loop on that. :

视图

newsletters = Newsletter.objects.prefetch_related('article_set').all()\
                    .order_by('-year', '-number')

return render_to_response('newsletter/newsletter_list.html',
                          {'newsletter_list': newsletters})

模板

{% block content %}
  {% for newsletter in newsletter_list %}
    <h2>{{ newsletter.label }}</h2>
    <p>Volume {{ newsletter.volume }}, Number {{ newsletter.number }}</p>
    <p>{{ newsletter.article }}</p>
    <ul>
    {% for a in newsletter.article_set.all %}
      <li>{{ a.title }}</li>
    {% endfor %}
    </ul>
  {% endfor %}
{% endblock %}

这篇关于遍历Django中的相关对象:遍历查询集或使用单行select_related(或prefetch_related)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆