【发布时间】:2013-01-18 20:54:51
【问题描述】:
我有一个方法定义如下:
def get_featured_books(cats=0):
"""
This method would return a list of featured books
"""
fbooks = list()
categories = models.Category.objects.annotate( bookcount=Count('book')).order_by('bookcount')[:cats].reverse()
for item in categories:
fbooks.append(item.book_set.latest('posted_date'))
return fbooks
我在主页视图上使用上述方法显示精选书籍列表。在模板中,我使用以下标签:
{% for book in featured %}
<h2>{{ book.title }}({{ book.category}})</h2>
<span class="authors">{{book.authors.all|join:','}}</span>
{% endfor %}
但这整个概念引起了很多质疑。例如,如果我想展示 10 本精选书籍:
categories = models.Category.objects.annotate( bookcount=Count('book')).order_by('bookcount')[:cats].reverse()
将进行一次查询。
for item in categories:
fbooks.append(item.book_set.latest('posted_date'))
将进行 10 次查询。
在模板中,{{ book.category}} 和 {{ book.authors.all }} 将为每本书分别进行 1 次查询,因此在我的场景中,上述两个标签将进行 20 次查询。这使得它总共有 30 个查询(仅显示 10 条记录的列表)。当然,我将在主页上显示其他内容,这些内容会产生额外的查询。
问题是我怎样才能减少(最低)否。查询以获取上述信息。通常的做法是什么?
(PS:我知道缓存,我知道信息可以被缓存,但我在这里的目的是学习如何进行有效的查询。)
更新:
正如KrzysiekSzularz 建议的那样,我尝试如下使用select_related 和prefetch_related,但django 调试工具栏仍然显示它进行了32 个查询。
def get_featured_books(cats=0):
"""
This method would return a list of featured books
"""
fbooks = list()
categories = models.Category.objects.select_related().annotate( bookcount=Count('book')).order_by('bookcount')[:cats].reverse()
for item in categories:
fbooks.append(item.book_set.prefetch_related('category').latest('posted_date'))
return fbooks
【问题讨论】:
-
将
select_related用于category和prefetch_related用于authors和book_set。您将得到 3 个查询。 -
@KrzysiekSzularz,感谢您的回复。我确实改用
select_related和prefetch_related但 DJDT 仍然显示 32 个查询,知道为什么吗? -
应用
prefetch_related后,您不能对查询进行任何修改。任何复制现有查询对象的操作都会中断预取。