【问题标题】:How to group by and aggregate conditional in Django ORM如何在 Django ORM 中分组和聚合条件
【发布时间】:2019-09-14 21:57:51
【问题描述】:

我有一个 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

有什么想法可以实现吗?

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

【问题讨论】:

  • 能否将Worklog 模型添加到您的问题中?
  • 哦,我一定错过了。我刚刚添加了它。谢谢!
  • 尝试删除第二个values( 'worker__fullname' )
  • 删除第二个 values( 'worker__fullname' ) 得到完全相同的结果

标签: django django-orm


【解决方案1】:

我自己搞定了。我之前不知道的功能是在聚合函数中使用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),否则总和将返回None(根据this 帖子)

【讨论】:

    猜你喜欢
    • 2018-08-19
    • 1970-01-01
    • 1970-01-01
    • 2020-09-09
    • 2021-03-04
    • 2021-12-13
    • 2019-11-15
    • 2010-11-01
    • 1970-01-01
    相关资源
    最近更新 更多