代码之家  ›  专栏  ›  技术社区  ›  Niladry Kar

Django:执行复杂注释和聚合时的问题

  •  4
  • Niladry Kar  · 技术社区  · 7 年前

    这就是模型:

    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)
    

    我想对特定日期范围内的“总采购量”进行按月计算,如果一个月内没有采购,则总采购量应为上个月的采购值。 如果在两个月内有采购,那么总采购量将是这两个月的总和…

    例子:

    假设用户给出的日期范围是4月到11月。

    如果4月购买2800美元,8月购买5000美元,10月购买6000美元。

    然后输出如下:

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

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

    谢谢你

    根据Raydel Miranda先生给出的答案。我已经做了以下工作

    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
    

    我想添加每个月的下一个迭代值“部分总计”。我想这能解决我的问题。

    有人知道怎么在Django表演吗?

    谢谢你

    2 回复  |  直到 7 年前
        1
  •  7
  •   Raydel Miranda    7 年前

    我在你的问题中注意到两件事:

    1. 结果按月排序。
    2. 购买总额可以是 blank null .

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

    你可以得到一个月的总数,你只需要处理 total_pushase 为空(作为旁注,没有任何意义 Purchase 哪里 total_purchase 为空,至少必须为0)。

    阅读有关 Django Conditional expressions 了解更多信息 When 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']
    

    您可以在函数中使用它来实现您想要的结果:

    import calendar
    import collections
    import dateutil
    
    def totals(start_date, end_date):
        """
        start_date and end_date are datetime.date objects.
        """
    
        results = collections.OrderedDict()  # Remember order things are added.
    
        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
        month_partial_total = 0
        while date_cursor < end_date:
            # The while statement implicitly orders results (it goes from start to end).
            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
    
            # Uncomment following line if you want result contains the month names
            # instead the month's integer values.
            # result[calendar.month_name[month_number]] = month_partial_total
    
            date_cursor += dateutil.relativedelta.relativedelta(months=1)
    
        return results
    

    因为Django 1.11可以解决这个问题 SubQueries 但我从未在同一个模型上使用过它进行子查询。

        2
  •  0
  •   Niladry Kar    7 年前

    解决方案

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

    我在自己的观点中做了以下的工作,它非常有效:

    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
    

    谢谢大家。

    推荐文章