Why doesn't this Django filter by 'annotate' variable work?

Viewed 277

I have this queryset in Django:

obj = Obj.objects.annotate(duration = F('date_end') - F('date_start')).order_by('duration')

The following works perfectly:

obj[0].duration

obj.aggregate(Sum('duration'))['duration__sum']

However filtering doesn't work in this case even though documentation says that it should:

obj = obj.filter( duration__gte = <a_class_datetime.timedelta> )  # doesn't work
obj = obj.filter( duration = 1 )   # doesn't work

This is the error I am getting:

TypeError: expected string or bytes-like object

My way to bypass this issue is to loop through the dataset - which is huge. Any tips as to why this is not working?

1 Answers

You need to use Python's timedelta instance while filtering,

from datetime import timedelta

obj = obj.filter(duration__gte=timedelta(days=10))

Apart from that, use ExpressionWrapper to specify the output_field so that you can avoid unwanted errors.

from django.db import models

# for annotation
annotated_queryset = Foo.objects.annotate(
    duration=models.ExpressionWrapper(models.F('date_end') - models.F('date_start'),
                                      output_field=models.DurationField()))

# for filtering
from datetime import timedelta

filtered_queryset = annotated_queryset.filter(duration__gte=timedelta(days=10))
Related