我有一个简报应用程序,其中一个简报在每个问题中都有多篇文章。我想在线显示一个摘要页面,列出时事通讯年份,数量和标签,然后在无序列表中显示问题中的所有文章。我对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>
非常简单。但是,我对编写视图的最佳方式感到困惑。是否使用:
zip()
然后在模板中迭代的两个列表select_related()
queryset prefetch_related()
queryset 我使用第一个选项工作:
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方面是否完全没有效率。如果有更快的方法,我很乐意不必动态列表然后zip()
将两个列表放在一起。
TIA。
答案 0 :(得分:43)
您现在正在采取的方法将严重效率低下,因为它会导致1 + N次查询。也就是说,1用于查询所有简报,然后每次评估n.article_set.all()
次结果时为1。因此,如果您在第一个查询中有100个Newletter对象,那么您将进行101次查询。
这是使用prefetch_related
的绝佳理由。它只会导致2个查询。一个获取通讯,一个批量获取相关文章。虽然你仍然可以完全按照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 %}