我有一个像这样的简单模型:
class Order(models.Model):
created = model.DateTimeField(auto_now_add=True)
total = models.IntegerField() # monetary value
我想逐月输出:
COUNT
)SUM
)我不确定攻击它的最佳方法是什么。我已经看到了一些相当可怕的额外选择查询,但我简单的想法告诉我,我可能会更好的只是迭代数字,从任意的开始年/月开始计算直到我到达当前月份,抛弃简单查询过滤该月份。更多数据库工作 - 减少开发人员压力!
对你来说最有意义的是什么?有没有一种很好的方法可以撤回快速的数据表?或者我的脏方法可能是最好的主意吗?
我正在使用Django 1.3。不确定他们最近是否为GROUP_BY
添加了更好的方法。
答案 0 :(得分:191)
Django 1.10及以上
Django文档列出了extra
,因为很快就弃用了。 (感谢你指出@seddonym,@ Lucas03)。我打开了一个ticket,这是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
旧版本
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')
编辑
答案 1 :(得分:16)
只是@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()
答案 2 :(得分:5)
另一种方法是使用ExtractMonth
。由于只返回了一个日期时间年值,因此使用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')
答案 3 :(得分:2)
metrics = {
'sales_sum': Sum('total'),
}
queryset = Order.objects.values('created__month')
.annotate(**metrics)
.order_by('created__month')
queryset
是订单列表,每月一个行,并结合销售总额:sales_sum
@Django 2.1.7
答案 4 :(得分:0)
这是我的脏方法。它很脏。
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
可能有更好的循环年/月的方法,但这并不是我真正关心的事情:)
答案 5 :(得分:0)
以下是您可以按任意时间段对数据进行分组的方法:
from django.db.models import F, Sum
from django.db.models.functions import Extract, Cast
period_length = 60*15 # 15 minutes
# Annotate each order with a "period"
qs = Order.objects.annotate(
timestamp=Cast(Extract('date', 'epoch'), models.IntegerField()),
period=(F('timestamp') / period_length) * period_length,
)
# Group orders by period & calculate sum of totals for each period
qs.values('period').annotate(total=Sum(field))
答案 6 :(得分:0)
我的数据库中有订单表。我要计算最近3个月每月的订单量
from itertools import groupby
from dateutil.relativedelta import relativedelta
date_range = datetime.now()-relativedelta(months=3)
aggs =Orders.objects.filter(created_at=date_range)\
.extra({'date_created':"date(created_at)"}).values('date_created')
for key , group in groupby(aggs):
print(key,len(list(group)))
created_at是日期时间字段。通过额外的功能,完成的工作是从日期时间值中获取日期。使用日期时间时,由于对象是在一天中的不同时间创建的,因此我们可能无法正确计数。
for循环将打印日期和计数
答案 7 :(得分:-2)
按月:
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'))
不要忘记导入计数
from django.db.models import Count
对于django&lt; 1.10 强>