Running a Django management command as a Cron job

July 20, 2017 01:39am
by Thomas Tran



Cron is a Linux utility that allows users to schedule autonomous tasks. Linux systems use Cron jobs internally to backup system logs, configurations, among other data that keep the system healthy. However, users can also specify their own Cron jobs to run custom tasks. Essentially, anything that can be run on the console (which is basically anything and everything) can be converted into a Cron job.

Django allows developers to create management commands that perform custom tasks. For instance, developers may find it easier to create a management command that changes certain model values rather than directly altering the database layer. This additional layer of abstraction abates human errors and makes the code easier to understand, which is a core tenet of Django.

It is possible to schedule management commands to run at specific times. By combining Cron and management commands, we can easily program this task.

First, let's set up a management command. In a Django app, create the following file: my_app/management/commands/reset_oranges.py. This set-up will allow us to directly call the file with the following command: python manage.py reset_oranges.

Our reset_oranges command will loop through all Orange models and reset the number in stock to 0, meaning that no oranges are available to sell. Our Fruit model is given below and can be found in my_app/models.py.

from django.db import models

class Orange(models.Model):
    num_in_stock = models.IntegerField(max_length=10, help_text="Number of oranges available in stock.")

Our command (contained within my_app/management/commands/reset_oranges.py) will be the following:

from django.core.management.base import BaseCommand
from my_app.models import Orange

class Command(BaseCommand):

    def clear_stock(self):
        all_oranges = Orange.objects.all()
        for orange in all_oranges:
            orange.num_in_stock = 0
            orange.save()

    def handle(self, *args, **options):
        self.clear_stock()

To run this command, input the following:

python manage.py reset_oranges 

When we run this command, Django by default calls the handle() method. Since we overrode this method, our handle() method calls the helper method clear_stock() that contains our business logic.

We are now able to run this command once. Since it's useful to reset the number of oranges in stock to zero at the end of everyday, we'll now create a Cron job so that this task is performed automatically at the end of every day.

I'll assume you're running Debian or its derivatives. To see all Cron jobs running on the current machine, input the following command:

sudo crontab -l

To edit the current jobs or to add new jobs, use the following command:

sudo crontab -e

Now add the following line to the file:

00 23 * * * /path/to/bin/python /path/to/project/manage.py reset_oranges

This will run reset_oranges at 11pm every night. Make sure that all paths in this file absolute and not relative. Similarly, if you are using log files in your Django management command, use absolute paths to specify the location of your log file.

Your Cron job should be all set up!