Home > Software engineering >  How to set field value expiration time?
How to set field value expiration time?

Time:12-31

I have model User like this:

class User(AbstractBaseUser, PermissionsMixin):
    myfield_choices = (('foo', 'First value'), ('bar', 'Second value')

    myfield = CharField(choices=choices)
    
    objects = BaseUserManager()

I set in the field myfield value foo. After I want to set in the field myfield value bar for 1 day and after this period expires, the value becomes foo again automatically.
How can I set that expiration time? Is there any native django instruments for this?

CodePudding user response:

I assume you are a bit new to Django, so I'll advise a solution that is not based on task queue (like celery or dramatiq).

For clearness, let's assume that we are implementing ban_user and unban_user mechanics. Firstly we have to update the User model:

class User(AbstractBaseUser, PermissionsMixin):
    class BanStatus(models.TextChoices):
        ACTIVE = "ACTIVE", "ACTIVE"
        BANNED_FOR_DAY = "BANNED_FOR_DAY", "BANNED_FOR_DAY"

    ban_status = models.TextField("Ban status", choices=BanStatus.choices)
    banned_for_day_at = models.DateTimeField("Banned for day at", null=True)

Then we have to implement the exact mechanics. I'd prefer to do it in some your-app-name/logic/ban_user.py file:

from django.utils import timezone
# And also an import of User.


def ban_user_for_day(user: User):
    user.ban_status = User.BanStatus.BANNED_FOR_DAY
    user.banned_for_day_at = timezone.now()
    user.save()


def revoke_ban_user_for_day(user: User):
    user.ban_status = User.BanStatus.ACTIVE
    user.banned_for_day_at = None
    user.save()

Thus we can call ban_user_for_day from views. As to revoke_ban_user_for_day, the simplest way to organize calling it is a Command which can be called periodically, with cron, for example. You can place it at your-app-name/management/commands/revoke_ban_user_for_day.py

from django.core.management import BaseCommand
from django.utils import timezone
# And also imports of User and revoke_ban_user_for_day.


class Command(BaseCommand):
    def handle(self, *args, **options):
        user_list_for_revoke = User.objects.filter(
            ban_status=User.BanStatus.ACTIVE,
            banned_for_day_at__lte=timezone.now() - timezone.timedelta(days=1)
        ).all()

        for user in user_list_for_revoke:
            revoke_ban_user_for_day(user)

That's all. If you'd set up this Command for running once a minute, the delay between the time when User should be unbanned and when it would be actually unbanned would be not greater than 1 minute.

  • Related