Django:进行复杂的注释和聚合时出现问题

时间:2019-01-11 07:36:08

标签: django django-models django-aggregation django-annotate

这是模型:

class Purchase(models.Model):
    date           = models.DateField(default=datetime.date.today,blank=False, null=True)
    total_purchase = models.DecimalField(max_digits=10,decimal_places=2,blank=True, null=True)

我要在特定日期范围内对“ total_purchase”进行按月计算,这样,如果一个月内没有购买,则总购买应为前一个月的购买价值 如果两个月内有购买,那么总购买将增加这两个...

示例:

假设用户指定的日期范围是从4月到11月。

如果四月份购买了2800美元,八月份购买了5000美元,十月份购买了6000美元。

然后输出将如下所示:

April      2800
May        2800
June       2800
July       2800
August     7800  #(2800 + 5000)
September  7800
October    13800 #(7800 + 6000)
November   13800

有人知道如何在Django查询中执行此操作吗?

谢谢

根据雷德尔·米兰达先生的回答。我已完成以下操作

import calendar
import collections
import dateutil

start_date = datetime.date(2018, 4, 1)
end_date = datetime.date(2019, 3, 31)

results = collections.OrderedDict()

result = Purchase.objects.filter(date__gte=start_date, date__lt=end_date).annotate(real_total = Case(When(Total_Purchase__isnull=True, then=0),default=F('tal_Purchase')))

date_cursor = start_date

while date_cursor < end_date:
    month_partial_total = result.filter(date__month=date_cursor.month).agggate(partial_total=Sum('real_total'))['partial_total']

    results[date_cursor.month] = month_partial_total

    if month_partial_total == None:
            month_partial_total = int(0)
    else:
            month_partial_total = month_partial_total

    date_cursor += dateutil.relativedelta.relativedelta(months=1)

    return results

但是现在输出是这样的(来自上面的示例):

April      2800
May        0
June       0
July       0
August     5000
September  0
October    6000
November   0

有没有人知道如何在几个月之间添加... 我想做类似的事情

e = month_partial_total + month_partial_total.next

我想添加每个month_partial_total的下一个迭代值。我认为这可以解决我的问题。

有人知道如何在Django中执行此操作吗?

谢谢

2 个答案:

答案 0 :(得分:7)

我在您的问题中指出了两件事:

  1. 结果按月排序。
  2. 购买总数可以是blanknull

基于这些内容,我将提出这种方法:

您可以获取给定月份的总数,您只需要处理total_pushase为null的情况(请注意,拥有{{1}的实例没有任何意义},其中Purchase为null,至少必须为0)。

阅读有关Django Conditional expressions的信息,以了解有关total_purchaseWhen的更多信息。

Case

您可以在函数中使用它来获得所需的结果:

# Annotate the filtered objects with the correct value (null) is equivalent
# to 0 for this requirement.

result = Purchase.objects.filter(date__gte=start_date, date__lt=end_date).annotate(
    real_total = Case(
        When(total_purchase__isnull=True, then=0),
        default=F('total_purchase')
    )
)

# Then if you want to know the total for a specific month, use Sum.
month_partial_total = result.filter(
    date__month=selected_month
).aggregate(
    partial_total=Sum('real_total')
)['partial_total']

由于Django 1.11可能能够解决此问题SubQueries,但我从未在同一模型上将其用于子查询。

答案 1 :(得分:0)

解决方案

根据雷德尔·米兰达先生的回答,终于我找到了解决问题的方法...

我已经完成了以下工作,并且效果很好:

import datetime
import calendar
import collections
import dateutil
start_date = datetime.date(2018, 4, 1)
end_date = datetime.date(2019, 3, 31)
results = collections.OrderedDict()
result = Purchase.objects.filter(date__gte=start_date, date__lt=end_date).annotate(real_total = Case(When(Total_Purchase__isnull=True, then=0),default=F('Total_Purchase')))
date_cursor = start_date
z = 0
while date_cursor < end_date:
    month_partial_total = result.filter(date__month=date_cursor.month).aggregate(partial_total=Sum('real_total'))['partial_total']
    # results[date_cursor.month] = month_partial_total
    if month_partial_total == None:
        month_partial_total = int(0)
        e = month_partial_total
    else:
        e = month_partial_total

    z = z + e

    results[date_cursor.month] = z

    date_cursor += dateutil.relativedelta.relativedelta(months=1)

 return results

谢谢大家。