Myzel394
Myzel394

Reputation: 1317

Django Filter if field is not None

I have a model where I can set expire_date. I want to filter the model and when there's a expire_date set it should filter if the expire_date is lower than now.

I tried it to do with Case and When but I can't filter in a When function, can I?

News.objects.all().annotate(is_expired=Case(When(F("expire_date") != None, then=False if F("expire_date") <= datetime.now() else True))).filter(is_expired=False)

Upvotes: 5

Views: 5242

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476624

You can, the condition should be a Q object, or you specify the condition through the named parameters:

from django.db.models import BooleanField, Case, Q, When

News.objects.annotate(
    is_expired=Case(
        When(
            condition=Q(expire_date__isnull=True) | Q(expire_date__gte=datetime.now()),
            then=True
        ),
        default=False,
        output_field=BooleanField()
    )
).filter(is_expired=False)

You can not write Python code with ternary operators, etc. and then hope that automagically it is transformed into an SQL query.

That being said, here you simply filter on the annotation, so you can just write this as:

News.objects.filter(Q(expire_date__isnull=True) | Q(expire_date__gte=datetime.now()))

this thus will include all News objects with expire_date equal to NULL, or where expire_date is greater than or equal to datetime.now(). The logic in your answer did not make much sense, since it would annotate is_expired with all non-null expire_dates that are null, or where expre_date is less than the current time.

Upvotes: 8

Related Questions