Alex Ford
Alex Ford

Reputation: 659

Django Execute Function When DateTimeField Equals Current Date and Time

So I have implemented a subscription product to my website.

When they start the subscription, the current date and time is stored into the database. When they cancel the subscription, a period of time is added onto the start date so I know when to cancel the subscription and change some values elsewhere.

This is fine, I know how to use Django and Python, however, I am stuck on the last bit of, when the cancel date comes around in the future.

Question: How do I execute a function when the cancel date (in the db) is equal to current date and time.

Below is an simple example of the model I will be using:

models.py

class Subscriptions(models.Model):
    subscription_id = models.AutoField(primary_key=True)
    start_date = model.DateTimeField(auto_now_add=True)
    cancel_date = model.DateTimeField(auto_now_add=False)
    person_id = model.ForeignKey('Persons')

class Persons(models.Model):
    person_id = models.AutoField(primary_key=True)
    value_to_change = models.BooleanField()

Before you ask I have not attempted any code as I couldn't find a solution for this problem. Thanks <3

Upvotes: 1

Views: 839

Answers (1)

Risadinha
Risadinha

Reputation: 16666

Without Celery, installed on UNIX system providing CRON (cron doku: e.g. https://www.computerhope.com/unix/ucrontab.htm):

  1. write a Command https://docs.djangoproject.com/en/2.1/howto/custom-management-commands/ that fetches the objects for which cancel_date is in the past and that have not been cancelled yet. (If you do the lookup with datetime.now() (a very precise lookup with the finest granularity), you would have to be more than lucky to find anything.)

You should add another date field that tells you when the system actually ran the cancellation, and you should allow both the cancel_date and cancelled_date to be null.

# models.py
class Subscriptions(models.Model):
    subscription_id = models.AutoField(primary_key=True)
    start_date = model.DateTimeField(auto_now_add=True)
    cancel_date = model.DateTimeField(auto_now_add=False, null=True)
    cancelled_date = model.DateTimeField(null=True)
    person_id = model.ForeignKey('Persons')

# under myapp/management/command/cancellation.py
class CancellationCommand(BaseCommand):
    def handle(self, *args, **options):
        now = datetime.now()
        to_cancel_qs = Subscriptions.objects.exclude(
            cancelled_date__isnull=False).filter(
            cancel_date__lte=now)
        for sub in to_cancel_qs.all():
            # do your cancelling
            sub.cancelled_date = now
            sub.save()
        # or: to_cancel_qs.update(cancelled_date=now)
        
  1. install a cron job that runs this command via ./manage.py your_command at a regular time

Upvotes: 3

Related Questions