Django агрегированное поле, но отфильтрованное по дате

Я пытаюсь аннотировать сумму другой модели, но отфильтрованную по дате.

У меня есть модели Employee и Shift, в Shift есть DecimalField dur, DateTimeField start и внешний ключ employee.

class Employee(models.Model):
    name = models.CharField(max_length=64)

class Shift(models.Model):
    employee = models.ForeignKey(Employee, on_delete=models.CASCADE)
    start = models.DateTimeField()
    dur = models.DecimalField(max_digits=4, decimal_places=2, default=0)

С помощью Employee.objects.all().annotate(Sum('shift__dur')) я могу сложить общую сумму всех смен, но как я могу отфильтровать эти смены, например, чтобы суммировать только смены в определенном диапазоне дат?

Заранее спасибо!

Вы можете фильтровать, например, с помощью:

Employee.objects.filter(
    shift__start__range=('2022-01-01', '2020-01-31')
).annotate(
    total=Sum('shift__dur')
)

Это покажет только сдвиги для января 2022. Более того, Employee без сдвигов для января 2022 будут отфильтрованы.

Вы также можете получить данные за неделю, например, с помощью:

from django.db.models.functions import TruncWeek

Shift.objects.values(
    'employee_id',
    week=TruncWeek('start')
).annotate(
    total=Sum('dur')
).order_by('employee_id', 'week')
<
<QuerySet [
    {'employee_id': 1, 'week': date(2022, 1, 3), 'total': Decimal('14.25')},
    {'employee_id': 1, 'week': date(2022, 1, 10), 'total': Decimal('13.02')},
    {'employee_id': 1, 'week': date(2022, 1, 17), 'total': Decimal('17.89')},
    {'employee_id': 2, 'week': date(2022, 1, 3), 'total': Decimal('57.3')},
    {'employee_id': 2, 'week': date(2022, 1, 17), 'total': Decimal('18.30')}
]>

Таким образом, получается агрегат по первичному ключу empoloyee и по неделе (неделя усекается, чтобы начинаться в понедельник), а в итоговом списке перечисляется сумма dur смен. Если для данной комбинации employee_id-week нет смен, то она не появится в наборе запросов. Таким образом, если вы хотите ввести нули для этих недель, вам придется выполнить некоторую постобработку.

Вернуться на верх