我有一个看起来像这样的模型:
class Category(models.Model): name = models.CharField(max_length=60) class Item(models.Model): name = models.CharField(max_length=60) category = models.ForeignKey(Category)
我想要为每个类别选择项目的计数(只是计数),所以在SQL中它就像这样简单:
select category_id, count(id) from item group by category_id
有没有相当于这样的"Django方式"?或者纯SQL是唯一的选择吗?我熟悉Django中的count()方法,但我不知道group by是如何适合的.
在这里,正如我刚刚发现的,是如何使用Django 1.1聚合API执行此操作:
from django.db.models import Count theanswer = Item.objects.values('category').annotate(Count('category'))
(更新:完整的ORM聚合支持现在包含在Django 1.1中.正如下面关于使用私有API的警告,此处记录的方法不再适用于1.1版本的Django.我没有挖出来找出原因;如果你在1.1或更高版本,你应该使用真正的聚合API.)
核心聚合支持已经存在于1.0中; 它只是没有文档记录,不受支持,并且还没有友好的API.但是这里是你如何使用它,直到1.1到达(风险自负,并完全了解query.group_by属性不是公共API的一部分,可能会改变):
query_set = Item.objects.extra(select={'count': 'count(1)'}, order_by=['-count']).values('count', 'category') query_set.query.group_by = ['category_id']
如果然后迭代query_set,则每个返回的值将是一个带有"category"键和"count"键的字典.
您不必在此处通过-count进行排序,只是为了演示它是如何完成的(它必须在.extra()调用中完成,而不是在queryset构造链的其他地方完成).此外,你也可以说count(id)而不是count(1),但后者可能更有效率.
另请注意,在设置.query.group_by时,值必须是实际的DB列名('category_id')而不是Django字段名('category').这是因为你正在调整查询内部的水平,其中所有内容都是数据库术语,而不是Django术语.
由于我对Django 1.1中的分组工作有点困惑,我想我会详细说明你如何使用它.首先,重复迈克尔所说的话:
在这里,正如我刚刚发现的,是如何使用Django 1.1聚合API执行此操作:
from django.db.models import Count theanswer = Item.objects.values('category').annotate(Count('category'))
还要注意你需要from django.db.models import Count
!
这将仅选择类别,然后添加一个名为的注释category__count
.根据默认顺序,这可能是您所需要的,但如果默认排序使用除此之外的字段category
将不起作用.原因是订购所需的字段也被选中并使每一行都是唯一的,因此您不会按照您想要的方式对其进行分组.解决此问题的一种快速方法是重置排序:
Item.objects.values('category').annotate(Count('category')).order_by()
这应该产生你想要的结果.要设置可以使用的注释的名称:
...annotate(mycount = Count('category'))...
然后,您将mycount
在结果中调用注释.
其他关于分组的事情对我来说非常简单.请务必查看Django聚合API以获取更多详细信息.