代码之家  ›  专栏  ›  技术社区  ›  Sergey Golovchenko

计数和分组依据的Django等价物

  •  87
  • Sergey Golovchenko  · 技术社区  · 17 年前

    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是唯一的选择?我对这本书很熟悉 计数() 方法,但我不知道如何使用 分组

    4 回复  |  直到 17 年前
        1
  •  132
  •   michael    17 年前

    正如我刚刚发现的,这里是如何使用Django 1.1聚合API实现这一点:

    from django.db.models import Count
    theanswer = Item.objects.values('category').annotate(Count('category'))
    
        2
  •  58
  •   Carl Meyer    17 年前

    ( :完整的ORM聚合支持现在包含在 Django 1.1 . 与下面关于使用私有API的警告一样,这里介绍的方法不再适用于Django的1.1后版本。我还没有弄清楚原因;如果您使用的是1.1或更高版本,您应该使用real aggregation 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']
    

    如果您随后迭代查询集,则每个返回值都将是一个带有“category”键和“count”键的字典。

    这里不必按-计数排序,这只是为了演示它是如何完成的(必须在.extra()调用中完成,而不是在queryset构造链的其他地方)。同样,您也可以说count(id)而不是count(1),但后者可能更有效。

    还请注意,在设置.query.group_by时,值必须是实际的DB列名('category_id'),而不是Django字段名('category')。这是因为您正在调整查询内部结构,使所有内容都以DB术语而不是Django术语表示。

        3
  •  57
  •   Daniel    17 年前

    因为我对Django1.1中的分组工作方式有点困惑,所以我想在这里详细介绍一下如何使用它。首先,重复迈克尔的话:

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

        4
  •  2
  •   S.Lott    17 年前

    这个怎么样?(慢的除外。)

    counts= [ (c, Item.filter( category=c.id ).count()) for c in Category.objects.all() ]
    

    它的优点是很短,即使它获取了很多行。


    编辑

    一个查询版本。顺便说一句,这是经常发生的 更快 然后在数据库中选择COUNT(*)。试试看。

    counts = defaultdict(int)
    for i in Item.objects.all():
        counts[i.category] += 1