How can I convert the value of a DurationField to its number of microseconds/minutes in a QuerySet?

Viewed 648

Suppose I have two models: Computer and DailyUsage. DailyUsage has a DurationField named usage_duration. On a QuerySet of Computers, I want to annotate the average daily usage in minutes. Each additional minute the computer has been used on average per day, the computer's "importance" increases.

I have seen examples* of people using ExpressionWrapper to convert a DurationField to its BigIntegerField representation, but attempting this:

average_in_duration_annotated = Computer.objects.annotate(
    avg=Avg("daily_usages__usage_duration", filter=Q(daily_usages__date__gte=one_month_ago))
)

average_in_minutes_annotated = average_annotated.annotate(
    avg_in_minutes=ExpressionWrapper(F("avg"), output_field=BigIntegerField()) / Value(10e6 * 60)
)

... results in:

{TypeError}int() argument must be a string, a bytes-like object or a number, not 'datetime.timedelta' when the QuerySet is evaluated.

Another example that fails the same way:

Computer.objects.annotate(
    total_usage_microseconds=Sum("daily_usages__usage_duration", output_field=BigIntegerField())
)

How can I convert the value of a DurationField to its number of microseconds in a QuerySet?

* Aggregate in django with duration field

1 Answers

Because I'm using postgres, I can use Seconds from django-pg-utils:

qs.annotate(
    avg_usage_minutes=Avg(
        Seconds(F("daily_usages__usage_duration")) / Value(60),
        filter=Q(daily_usages__date__gte=one_month_ago)
    )
)
Related