Django:按月查询组

ald*_*ido 15 python django postgresql

如何在不使用额外的情况下按月计算总数?

我目前正在使用:

  • django 1.8
  • postgre 9.3.13
  • Python 2.7

例.

在此输入图像描述

到目前为止我尝试过的.

#Doesn't work for me but I don't mind because I don't want to use extra
truncate_month = connection.ops.date_trunc_sql('month','day')
invoices = Invoice.objects.filter(is_deleted = False,company = company).extra({'month': truncate_month}).values('month').annotate(Sum('total'))

----
#It works but I think that it's too slow if I query a big set of data
for current_month in range(1,13):
    Invoice.objects.filter(date__month = current__month).annotate(total = Sum("total"))
Run Code Online (Sandbox Code Playgroud)

而这一个,答案似乎很好,但我无法导入TruncMonth模块.

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


PS我知道这个问题已被多次询问,但我没有看到任何答案.

谢谢!


解决方案:

感谢@ Vin-G的回答.

在此输入图像描述

Vin*_*n-G 24

首先,你必须创建一个可以为你提取月份的函数:

from django.db import models
from django.db.models import Func

class Month(Func):
    function = 'EXTRACT'
    template = '%(function)s(MONTH from %(expressions)s)'
    output_field = models.IntegerField()
Run Code Online (Sandbox Code Playgroud)

之后你需要做的就是

  1. 用月份注释每一行
  2. 使用带注释的月份对结果进行分组 values()
  3. 使用总计的总和来注释每个结果 Sum()

重要提示:如果模型类具有元选项中指定的默认顺序,则必须添加空order_by()子句.这是因为https://docs.djangoproject.com/en/1.9/topics/db/aggregation/#interaction-with-default-ordering-or-order-by

order_by()在选择输出数据时,将使用在查询集的一部分中提到的字段(或在模型的默认排序中使用的字段),即使它们未在values()调用中另外指定.这些额外字段用于将"喜欢"结果组合在一起,并且它们可以使其他相同的结果行看起来是分开的.

如果您不确定,您可以添加空order_by()子句,无任何不利影响.

from django.db.models import Sum

summary = (Invoice.objects
              .annotate(m=Month('date'))
              .values('m')
              .annotate(total=Sum('total'))
              .order_by())
Run Code Online (Sandbox Code Playgroud)

请参阅此处的完整要点:https://gist.github.com/alvingonzales/ff9333e39d221981e5fc4cd6cdafdd17

如果您需要更多信息:

有关创建自己的Func类的详细信息:https://docs.djangoproject.com/en/1.8/ref/models/expressions/#func-expressions

有关values()子句的详细信息,(注意它与子句顺序的annotate()交互方式):https: //docs.djangoproject.com/en/1.9/topics/db/aggregation/#values

annotate()和values()子句应用于查询的顺序非常重要.如果values()子句在annotate()之前,则将使用values()子句描述的分组计算注释.

  • 您应该直接使用“ExtractMonth”或“TruncMonth”。`从 django.db.models.functions 导入 ExtractMonth,TruncMonth` (2认同)

小智 9

result = (
    invoices.objects
        .all()
        .values_list('created_at__year', 'created_at__month')
        .annotate(Sum('total'))
        .order_by('created_at__year', 'created_at__month')
)
Run Code Online (Sandbox Code Playgroud)

  • 不鼓励仅使用代码回答,当您添加一些上下文来解释如何解决问题时,答案价值会增加。 (2认同)

sch*_*ggl 5

itertools.groupby 是 Python 中的高性能选项,可以与单个 db 查询一起使用:

from itertools import groupby

invoices = Invoice.objects.only('date', 'total').order_by('date')
month_totals = {
    k: sum(x.total for x in g) 
    for k, g in groupby(invoices, key=lambda i: i.date.month)
}
month_totals
# {1: 100, 3: 100, 4: 500, 7: 500}
Run Code Online (Sandbox Code Playgroud)

我不知道纯 django ORM 解决方案。该date__month过滤器是非常有限的,并且不能被使用在valuesorder_by