Reputation: 1317
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
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 New
s 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_date
s that are null, or where expre_date
is less than the current time.
Upvotes: 8