Как отобразить объект 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'])