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 нет смен, то она не появится в наборе запросов. Таким образом, если вы хотите ввести нули для этих недель, вам придется выполнить некоторую постобработку.