Django:按日期分组(日,月,年)

Oli*_*Oli 78 django django-aggregation

我有一个像这样的简单模型:

class Order(models.Model):
    created = model.DateTimeField(auto_now_add=True)
    total = models.IntegerField() # monetary value
Run Code Online (Sandbox Code Playgroud)

我想逐个输出:

  • 一个月有多少销售额(COUNT)
  • 合并值(SUM)

我不确定攻击它的最佳方法是什么.我已经看到了一些相当可怕的额外选择查询,但我简单的想法告诉我,我可能会更好的只是迭代数字,从任意的开始年/月开始计算直到我到达当前月份,抛弃简单查询过滤该月份.更多数据库工作 - 减少开发人员的压

什么对你最有意义?有没有一种很好的方法可以撤回快速的数据表?或者我的脏方法可能是最好的主意?

我正在使用Django 1.3.不确定他们最近是否添加了更好的方式GROUP_BY.

tba*_*ack 206

Django 1.10及以上

Django文档列表很快就extra弃用了.(感谢你指出@seddonym,@ Lucas03).我开了一张票,这是jarshwah提供的解决方案.

from django.db.models.functions import TruncMonth
from django.db.models import Count

Sales.objects
    .annotate(month=TruncMonth('timestamp'))  # Truncate to month and add to select list
    .values('month')                          # Group By month
    .annotate(c=Count('id'))                  # Select the count of the grouping
    .values('month', 'c')                     # (might be redundant, haven't tested) select month and count 
Run Code Online (Sandbox Code Playgroud)

旧版本

from django.db import connection
from django.db.models import Sum, Count

truncate_date = connection.ops.date_trunc_sql('month', 'created')
qs = Order.objects.extra({'month':truncate_date})
report = qs.values('month').annotate(Sum('total'), Count('pk')).order_by('month')
Run Code Online (Sandbox Code Playgroud)

编辑

  • 添加计数
  • 添加了django> = 1.10的信息

  • 哦,是的,这比我的hacktastrophe更有意义.有一些要点. (25认同)
  • 如果上述查询不起作用,请使用`order_by()` (8认同)
  • 谢谢,效果很好.1.10之前版本的角点案例:如果一个人加入/过滤其他可能具有相同字段的模型(例如:timestamp),则必须完全限定字段 - "{}.timestamp'.format(model._meta) .db_table)` (2认同)

Ran*_*ani 24

只是@tback回答的一小部分:它对我来说不适用于Django 1.10.6和postgres.我在最后添加了order_by()来修复它.

from django.db.models.functions import TruncMonth
Sales.objects
    .annotate(month=TruncMonth('timestamp'))  # Truncate to month and add to select list
    .values('month')                          # Group By month
    .annotate(c=Count('id'))                  # Select the count of the grouping
    .order_by()
Run Code Online (Sandbox Code Playgroud)


Tur*_*tle 6

另一种方法是使用ExtractMonth。由于仅返回一个datetime年值,因此在使用TruncMonth时遇到了麻烦。例如,仅返回了2009年的几个月。ExtractMonth完美地解决了这个问题,可以像下面这样使用:

from django.db.models.functions import ExtractMonth
Sales.objects
    .annotate(month=ExtractMonth('timestamp')) 
    .values('month')                          
    .annotate(count=Count('id'))                  
    .values('month', 'count')  
Run Code Online (Sandbox Code Playgroud)

  • 一旦您的数据跨越多年,这种方法就不起作用,因为每年的月份保持不变,导致即使年份本身不同,它们也会分组在一起。 (2认同)