Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to delete a record after a certain time of it's creation in Django?

I am building an application that has a 'Story Feature' which is quite similar to Instagram's story feature, So I want to delete a story after 24 hours of its creation. So if a story was created on 12:00 PM 1 January 2021, I want to delete it automatically at 12:00 PM 2 January, 2021. I am using django3.1

My Model:

class Story(models.Model):
    user = models.ForeignKey(to=User, on_delete=models.CASCADE)
    text = models.CharField(max_length=200)
    image = models.ImageField(blank=True, null=True)
    video = models.FielField(blank=True, null=True)
    created_at = models.DateTimeField(auto_now_add=True)
    expiration_time = models.DateTimeField()

I want to delete every record after their particular expiration time.

[Expiration time is set in a post_save function ]

like image 367
Khan Asfi Reza Avatar asked Oct 20 '25 11:10

Khan Asfi Reza


2 Answers

The most robust way to do this is typically a combination of filtering, and removing the items with a task you run every hour/day/week.

We thus can retrieve the items that are not yet expired with:

from django.db.models.functions import Now

stories = Story.objects.filter(expiration_time__lt=Now())

If you need to filter often, it might be more interesting to make a manager [Django-doc] for this.

from django.db import models
from django.db.models.functions import Now

class StoryManager(models.Manager):

    def get_queryset(self, *args, **kwargs):
        return super().get_queryset(*args, **kwargs).filter(
            expiration_time__lt=Now()
        )


class Story(models.Model):
    # …
    xpiration_time = models.DateTimeField(db_index=True)
    
    objects = StoryManager()

The db_index=True part [Django-doc] will normally improve performance to filter expired objects.

Of course this does not remove the elements, it simply will not retrieve these (and thus if you filter these in the views, then you will not see these).

You can make a periodic task, for example a cronjob [wiki] that will run every day, week, month, hour to remove the elements. You can do this by defining a management command [Django-doc]:

# app_name/management/commands/remove_expired_stories.py

from django.core.management.base import BaseCommand
from django.db.models.functions import Now

from app_name.models import Story

class Command(BaseCommand):
    help = 'Remove expired stories'

    def handle(self, *args, **options):
        Story._base_manager.filter(expiration_time__gte=Now()).delete()

Then you can manually run:

python3 manage.py remove_expired_stories

or you can schedule this task to run periodically. This is more robust: if for some reason the scheduler does no longer work, then the filtering will still prevent that you can see the Storys that are expired. It is also simpler and more efficient than scheduling an expiration script per story, especially since if later the expiration time changes, it will be quite complicated to remove the scheduled items, and reschedule these.

like image 120
Willem Van Onsem Avatar answered Oct 22 '25 02:10

Willem Van Onsem


I have learned that it simple solutions are often better than more beautiful, complex ones.

If this were me, I would run a scheduled process that runs once an hour and checks each row in the sql table. Then, check if post time was greater than 24 hours ago.

If you really want to get fancy, I would recommend Redis to create a scheduled process upon creation of the post. Schedule a task in 24 hours that deletes that particular post.

like image 28
Thatcher Thornberry Avatar answered Oct 22 '25 00:10

Thatcher Thornberry



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!