Django:优化查询

时间:2010-12-31 04:33:14

标签: django

我想列出每个列表的项目数。如何在单个查询中找到此数字,而不是每个列表的查询?

以下是我当前模板代码的简化版本:

{% for list in lists %}
<li>
{{ listname }}:
{% with list.num_items as item_count %}
{{ item_count }} item{{ item_count|pluralize }}
{% endwith %}
</li>
{% endfor %}

列表传递为:List.objects.filter(user = user)

和num_items是List模型的属性:

def _get_num_items(self):
    return self.item_set.filter(archived=False).count()
num_items = property(_get_num_items)

此查询SELECT COUNT(*) FROM "my_app_item" WHERE... n次,其中n是列表数。可以在这里进行一次查询吗?

2 个答案:

答案 0 :(得分:1)

您应该在视图中执行此操作并发送字典。

Model.objects.values_list('item').annotate(Count('num_items'))

这将生成与您发布的SQL相同(或等效)的SQL。

答案 1 :(得分:1)

在下文中,我尝试考虑所有约束:过滤List的字段,Item的字段,计算项目和按列表分组。

我看到的解决方案是你可以使用values()(这里是django doc:http://docs.djangoproject.com/en/dev/topics/db/aggregation/#values

from django.db.models import Count
lists = list(List.objects.filter(user=user))
items=Item.objects.values(list).filter(archived=False,list__in=lists).annotate(count=Count("id")) 
#you will get a list of dicts of the form [{'count':2,'list':5},...] where 5 is the id of the list
#now, you can match you list with you item counts in python
list_items_count_dict={}
for item in items:
    list_items_count_dict[item['list']]=item['count']
for list in lists : 
    list.item_count = list_items_count_dict.get(list.id)

这将只生成2个查询,一个用于获取列表,另一个用于计算项目计数。之后,您将有两个循环(可能被列表推导单行替换),但仅适用于您感兴趣的列表。

之后,在您的模板中,您可以使用

{{list.item_count}}

可能有更优雅的选择,但这就是我现在所发现的。我也确定您可以使用自定义sql将查询数量减少到一个。

免责声明:我没有测试过此代码,但我在类似的模型上测试了类似的代码。您可能会遇到问题,因为list是Python语言的关键字之一。