2

I have a model:

class Document(models.Model):
    expiry_date = models.DateField()

How can I build a query which fetches all documents and give them annotation whether the expiry date has passed or not? I tried this:

today = timezone.now.date()

Document.objects.annotate(
    expired=Value(
        F('expiry_date')<today, 
        BooleanField()
    )
)

But it raises an error: TypeError: unorderable types: F() < datetime.date() How can I compare value from F() expression with the date?

Also, I'd like to avoid SQL and .extra()

3 Answers 3

2

There's no need to do that in the database. Put it in a model method:

class Document(models.Model):
    expiry_date = models.DateField()

    def expired(self):
        return self.expiry_date < timezone.now.date()
Sign up to request clarification or add additional context in comments.

2 Comments

Shouldn't it be self.expiry_date
I need to do it in the queryset because later I want to be able to call .order_by('expired')
1

You can use a conditional annotation.

Tested with Django 1.11.10.

from django.db.models import BooleanField, Case, When  
from django.utils import timezone

Document.objects.annotate(
    expired=Case(
        When(expiry_date__lt=timezone.now(), then=True),
        default=False,
        output_field=BooleanField()
    )
).order_by('expired')

Comments

0

This works for Django >= 2, didn't check for previous versions

from django.db import models
from django.db.models import ExpressionWrapper, Q
from django.db.models.functions import Now

Document.objects.annotate(
    expired=ExpressionWrapper(Q(expiry_date__lt=Now()),
    output_field=models.BooleanField())
)

source: https://stackoverflow.com/a/57114224/11193405

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.