在Django中遍历相关对象:循环遍历查询集或使用与select相关(或与prefetch相关)的一行程序

2024-05-07 11:49:49 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个时事通讯应用程序,其中一个时事通讯有多篇文章在每个问题。我想在网上显示一个摘要页面,其中列出了时事通讯的年份、卷和标签,然后在无序列表中显示该期的所有文章。我对Django还不太熟悉,所以我想确定最好的方法。

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

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)

我想在网上看到的是:

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

很简单。然而,我对写我观点的最佳方式感到困惑。是否使用:

  • 两个列表,然后在模板中迭代
  • 使用select_related()查询集
  • 使用prefetch_related()查询集

我用第一个选项让它工作:

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

然后使用以下模板进行渲染:

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方面完全没有效率。如果有一个更快的方法,我希望不必在飞行中列出一个列表,然后把这两个列表放在一起。

蒂亚。


Tags: 列表modelsarticlelih2ularticlesmax
1条回答
网友
1楼 · 发布于 2024-05-07 11:49:49

您现在所做的方法将非常低效,因为它将导致1+N个查询。也就是说,一个用于查询所有时事通讯,然后一个用于每次计算这些n.article_set.all()结果。因此,如果在第一个查询中有100个Newletter对象,则将执行101个查询。

这是使用prefetch_related的一个很好的理由。它只会导致两个查询。一个是获取时事通讯,一个是批量获取相关文章。尽管您仍然完全能够继续执行zip来组织它们,但它们已经被缓存,因此实际上您可以直接将查询传递到模板并在模板上循环。以下内容:

查看

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

相关问题 更多 >