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

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

class Order(models.Model): created = model.DateTimeField(auto_now_add=True) total = models.IntegerField() # monetary value 

我想输出一个按月分类的:

  • 一个月内有多less次销售( COUNT
  • 合并值( SUM

我不知道什么是攻击这个最好的方法是。 我已经看到了一些相当吓人的额外select查询,但我的简单头脑告诉我,我可能会更好的迭代数字,从任意开始的一年/一个月开始计数,直到我到达当前月份,抛出简单查询当月的过滤。 更多的数据库工作 – 减less开发人员压力

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

我使用的是Django 1.3。 不知道他们最近是否添加了一个更好的方法来GROUP_BY

Django 1.10及以上版本

Django文档列出extra 不久,将被弃用 。 (感谢您指出@seddonym,@ Lucas03)。 我打开了一张票 ,这是强制性提供的解决scheme。

 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 .values('month', 'c') # (might be redundant, haven't tested) select month and count 

较旧的版本

 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') 

编辑

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

只是一个小补充@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() 

另一种方法是使用ExtractMonth 。 由于只返回一个date时间年值,所以我使用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') 

这是我肮脏的方法。 它是脏的。

 import datetime, decimal from django.db.models import Count, Sum from account.models import Order d = [] # arbitrary starting dates year = 2011 month = 12 cyear = datetime.date.today().year cmonth = datetime.date.today().month while year <= cyear: while (year < cyear and month <= 12) or (year == cyear and month <= cmonth): sales = Order.objects.filter(created__year=year, created__month=month).aggregate(Count('total'), Sum('total')) d.append({ 'year': year, 'month': month, 'sales': sales['total__count'] or 0, 'value': decimal.Decimal(sales['total__sum'] or 0), }) month += 1 month = 1 year += 1 

可能有更好的循环年/月的方式,但这不是我真正关心的:)

按月份:

  Order.objects.filter().extra({'month':"Extract(month from created)"}).values_list('month').annotate(Count('id')) 

按年份:

  Order.objects.filter().extra({'year':"Extract(year from created)"}).values_list('year').annotate(Count('id')) 

白天:

  Order.objects.filter().extra({'day':"Extract(day from created)"}).values_list('day').annotate(Count('id')) 

不要忘记导入Count

 from django.db.models import * 

对于Django <1.10