Как отобразить объект timedelta в сгруппированном наборе запросов как поле продолжительности с помощью Django REST Framework?

У меня есть AssigneeLog класс модели, который хранит часы входа и выхода пользователя для каждой задачи.

from django.db import models
from django.utils import timezone


class AssigneeLog(models.Model):
    topic = models.ForeignKey(to=Topic, on_delete=models.CASCADE, blank=True)
    assignee = models.ForeignKey(to=User, on_delete=models.CASCADE, blank=True,
                                 help_text='Saved in case topic assignee is changed.')
    time_in = models.DateTimeField(default=timezone.now, blank=True, help_text='Default to current time.')
    time_out = models.DateTimeField(null=True, blank=True, help_text='Null at the start of time-in.')

Я хочу вывести список AssigneeLogs, сгруппированный по дате, и подсчитать, сколько времени ежедневно тратится на каждую комбинацию пользователь-задача. Мне это удается, но аннотированное значение total_time отображается в секундах, хотя я установил для аргумента output_field значение django.db.models.DurationField.
. Когда набор запросов не сгруппирован, я могу сделать это с помощью сериализации набора запросов, используя класс ModelSerializer с rest_framework.serializers.DurationField.
. Дополнительный метод действия DRF представления:

from django.db import models
from django.db.models import F, Sum
from django.db.models.functions import TruncDate
from rest_framework.response import Response
from zoneinfo import ZoneInfo


@action(methods=['post'], detail=False)
def get_report(self, request):
    serializer = self.get_serializer(data=request.data)
    serializer.is_valid(raise_exception=True)
    datetime_from = serializer.validated_data.get('datetime_from')  # ex: "2022-08-01T00:00:00"
    datetime_to = serializer.validated_data.get('datetime_to')  # ex: "2022-08-22T09:00:00"
    request_tz = serializer.validated_data.get('timezone')  # ex: "Etc/GMT+7"

    logs = AssigneeLog.objects.filter(
        time_in__gte=datetime_from, time_out__lte=datetime_to
    ).annotate(
        date=TruncDate('time_in', tzinfo=ZoneInfo(request_tz)),  # truncate to date with tz and add to select list.
    ).order_by('date').values('date').annotate(
        total_time=Sum(F('time_out')-F('time_in'), output_field=models.DurationField())
    ).values('topic__id', 'topic__name', 'topic__description', 'assignee__name', 'date', 'total_time')

    return Response(data=logs)

Выход:

[
    {
        "topic__id": 1,
        "topic__name": "First Task",
        "topic__description": "Task #1 description.",
        "assignee__name": "A user full-name",
        "date": "2022-08-02",
        "total_time": "32400.0"  --> desired result is "09:00:00"
    },
    ...
]

Я нашел способ с циклом queryset values и обновлением total_time каждого экземпляра вручную. Но есть ли лучший способ сделать это в одном и том же операторе queryset?

for log in logs:
    log['total_time'] = str(log['total_time'])
Вернуться на верх