如何在Django ORM中分组并聚合条件

问题描述 投票:1回答:1

我有一个Django查询来获得每位员工每天平均工作时间(每天可能有多个工作日志)。我想在工作日和周末工作中分开这些。

这是工作日志模型:

class Worklog(models.Model):
    worker = models.ForeignKey(Person, on_delete=models.CASCADE)
    day = models.DateField(null=False, blank=False)
    effort = models.FloatField()
    comment = models.TextField(null=True)
    project = models.ForeignKey(Project, on_delete=models.CASCADE)

我尝试过以下方法:

    qs = Worklog.objects.filter(
                day__range=[start,end]
            ).values(
                'worker__fullname'

            ).annotate(
                weekday=Case(
                    When(Q(day__week_day=1) | Q(day__week_day=7), then=1),
                    default=0,
                    output_field=IntegerField(),
                )
            ).values(
                'worker__fullname'
            ).annotate(
                weekdayAvg=Case(
                    When(Q(weekday=0), then=Cast(
                    Sum('effort')/Count('day', distinct=True)/60/60, FloatField()
                )),
                    default=0,
                    output_field=FloatField(),
                ),
                weekendAvg=Case(
                    When(Q(weekday=1), then=Cast(
                    Sum('effort')/Count('day', distinct=True)/60/60, FloatField()
                )),
                    default=0,
                    output_field=FloatField(),
                )
            ).order_by('worker__fullname')

这给了我结果

     weekdayAvg  weekendAvg                        worker__fullname
0      9.125000        0.00                        Klaus
1      0.000000       11.00                        Klaus
2      6.977273        0.00                        Peter
3      7.827586        0.00                        Carl
4      0.000000       13.00                        Carl
5      8.169643        0.00                        Chris
6      0.000000        2.25                        Chris

但是,预期的结果更像是:

     weekdayAvg  weekendAvg                        worker__fullname
0      9.125000        11.00                       Klaus
1      6.977273        0.00                        Peter
2      7.827586        13.00                       Carl
3      8.169643        2.25                        Chris

任何想法如何实现?

我也很高兴我的查询简化了一些。谢谢!

django django-orm
1个回答
0
投票

我自己管理了。我以前不知道的特征是在聚合函数中使用filter=参数(SumCount等)

    qs = Worklog.objects.filter( 
            day__range=[start,end] 
        ).values( 
            'worker__fullname' 
        ).annotate( 
            weekdayAvg=Cast(Coalesce(Sum('effort', filter=(~Q(day__week_day=1) & ~Q(day__week_day=7)))/Count('day', distinct=True, filter=(~Q(day__week_day=1) & ~Q(day__week_day=7)))/60/60, 0), FloatField()),
            weekdayCnt=Cast(Coalesce(Count('day', distinct=True, filter=(~Q(day__week_day=1) & ~Q(day__week_day=7))), 0), FloatField()),
            weekendAvg=Cast(Coalesce(Sum('effort', filter=(Q(day__week_day=1) | Q(day__week_day=7)))/Count('day', distinct=True, filter=(Q(day__week_day=1) | Q(day__week_day=7)))/60/60, 0), FloatField()),
            weekendCnt=Cast(Coalesce(Count('day', distinct=True, filter=(Q(day__week_day=1) | Q(day__week_day=7))), 0), FloatField()),
        ).order_by('weekdayAvg', 'worker__fullname')

另外我添加了Coalesce(..., 0)as,其他Sum将返回None(根据this帖子)

© www.soinside.com 2019 - 2024. All rights reserved.