Search code examples
djangoeventsschedule

Django - Scheduled event


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....
    [...]

Solution

  • 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().