jangeador
jangeador

Reputation: 604

Using django 1.8 duration field to annotate a set of django objects

I am reading the documentation for django duration field and I cannot figure out how I can use this to annotate a set of django objects with the duration. The docs say that the db stores durations as integer and to aggregate it needs to be converted to timedelta like so:

timedelta(microseconds=list.aggregate(sum=Sum('duration'))['sum'])

My problem is that I am not sure how to use this expression as an annotation for a set of django objects. The documentation can be found here

Thanks in advance.

Upvotes: 1

Views: 1734

Answers (1)

Anentropic
Anentropic

Reputation: 33833

I am not sure how to use this expression as an annotation for a set of django objects

The short answer is: you can't.

If you're talking about annotating a queryset with sums, then I assume the duration field is on a related model (via many-to-many or reverse foreign key relation) and you want to get the sums of durations for each row of the parent model.

You can annotate the queryset with int duration values in microseconds like so:

qs = MyModel.objects.annotate(sum=Sum('related_model__duration'))

Alternatively you might have the duration field on MyModel directly but are aggregating (i.e. an SQL GROUP BY query):

qs = MyModel.objects.values('grouped_field').annotate(sum=Sum('duration'))

Either way, to convert these to timedeltas you could iterate over the queryset and modify the instances:

for obj in qs:
    obj._timedelta = timedelta(microseconds=obj.sum)

Looking at this code it occurs to me I'd prefer to make this a property on the model, eg:

class MyModel(models.Model):
    # ...

    @property
    def timedelta(self):
        try:
            return timedelta(microseconds=self.sum)
        except AttributeError:
            # instance was not annotated (from a regular queryset)
            return None

Then you don't need to do the extra loop over the queryset.

Upvotes: 1

Related Questions