I would like the status
of this model change when the current date exceeds the expiration_date
. I was reading about background tasks and Asynchronous Tasks with Celery ... Am I going the right way? Is there a more direct way of doing this? If anyone can give me a tip or something to follow I would be grateful. Thanks for listening.
class MyModel(models.Model):
status = models.BooleanField...
expiration_date = models.DateField....
[...]
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()
.