Django Annotate-沿着多个.annotate()函数进行分组

时间:2016-09-07 21:13:29

标签: django django-queryset

我有以下经理,该工作正常。

def by_customer_and_date(self, start_date, end_date):

    qs = self.model.objects.filter(
        date__range=(start_date, end_date)
    ).values(
        "customer__name"
    ).annotate(
        grand_total_cogs=Sum('total_cogs'),
        total_sales=Sum('value'),
        total_profit=Sum('profit'),
        total_kgs=Sum('qty_applied'),
        current_balance=Sum('sale__receiptallocation__qty_applied')
    ).order_by('-total_kgs')

使用.values("customer__name")

按客户名称properly grouped结果

但是,我想做的是:

def by_customer_and_date(self, start_date, end_date):

    qs = self.model.objects.filter(
        date__range=(start_date, end_date)
    ).values(
        "customer__name"
    ).annotate(
        grand_total_cogs=Sum('total_cogs'),
        total_sales=Sum('value'),
        total_profit=Sum('profit'),
        total_kgs=Sum('qty_applied'),
        current_balance=Sum('sale__receiptallocation__qty_applied')
    ).annotate(
         margin=Case(
             When(total_sales=0, then=0),
             default=(F('profit')) / (F('value'))*100
         )
     ).order_by('-total_kgs')

我使用带注释的值来计算其分母可能为零的另一个值(因此使用Case(When))。当我添加此部分时,.values("customer__name")函数会失去它的效果,并显示每个单独的项目。

我尝试将.values("customer__name")部分移到最后(添加了对每个字段名称的明确引用),但问题仍然存在。

这是预期的行为吗?有没有办法解决它?

1 个答案:

答案 0 :(得分:0)

我已确定第二个annotate()必须放在表达式的最后。我的例子中这些的正确顺序应该如下:

self.model.objects.filter().values().annotate().order_by().annotate()

结果如下:

def by_customer_and_date(self, start_date, end_date):

    qs = self.model.objects.filter(
        date__range=(start_date, end_date)
    ).values(
        "customer__name"
    ).annotate(
        grand_total_cogs=Sum('total_cogs'),
        total_sales=Sum('value'),
        total_profit=Sum('profit'),
        total_kgs=Sum('qty_applied'),
        current_balance=Sum('sale__receiptallocation__qty_applied'),
    ).order_by(
        '-total_kgs'
    ).annotate(
        final_margin=Case(
            When(total_sales=0, then=0),
            default=(Sum(F('profit')) / Sum(F('value')))*100
        )
    )

    return qs