You do not need to store the status in the model, you can simply .annotate(..) [Django-doc] it, so if the model looks like:
class MyModel(models.Model):
expiration_date = models.DateField(db_index=True)
so without a status field. Then you can make an annotation with:
from django.db.models import BooleanField, ExpressionWrapper, Q
from django.db.models.functions import Now
MyModel.objects.annotate(
satus=ExpressionWrapper(
Q(expiration_date__gt=Now()),
output_field=BooleanField()
)
)
The MyModel objects that arise from this queryset will have an extra attribute .status that is True if the expiration_date is in the future.
If you need this often, you can make a manager [Django-doc] that automatically annotates the items each time you access MyModel.objects:
from django.db.models import BooleanField, ExpressionWrapper, Q
from django.db.models.functions import Now
class MyModelManager(models.Manager):
def get_queryset(self, *args, **kwargs):
super().get_queryset(*args, **kwargs).annotate(
satus=ExpressionWrapper(
Q(expiration_date__gt=Now()),
output_field=BooleanField()
)
)
class MyModel(models.Model):
expiration_date = models.DateField(db_index=True)
objects = MyModelManager()
This does not require scheduled tasks, which are hard to manage: what if you later edit the expiration_date, then you need to somehow "remove" the task already scheduled and schedule a new one, which can be "tricky". If the scheduled task is already completed you then have to "undo" it.
By using annotations, you make sure that status is simply based on the value of expiration_date compared to Now().