Django Management Commands via Cron
You want to periodically run a Django management command. How do you go about it?
Let’s get to it.
app_folder > management > commands > our_command_name.pyYou have a Django project, say,
MyProject. You have an app called,
main. Create in this
main folder a
management folder. Remember to add an
__init__.py in this
commands folder within the
management folder, and include an
__init__.py in this folder too.
You only need to include the
__init__.pythings when using Python less than version 3.3
Let’s say we want to delete items created some 3 or 6 months past automatically. One way is to create a management command, which would be run, say daily, clearing these objects for us.
In the above, you see the
cleanpackages.pyfile in the
The name you give to the file within this
commands folder becomes the command you would invoke on the command line.
So in our above example, we would invoke it as
python manage.py cleanpackages 3month
Here’s what our
cleanpackages.py file might contain:
I am not doing anything supernatural here. The details are within this doc page: http://devdocs.io/django~1.11/howto/custom-management-commands
from datetime import datetime, timedelta from django.utils import timezone from django.core.management.base import BaseCommand, CommandError from main.models import Package class Command(BaseCommand): help = 'Clears packages older than 90 days from today' def add_arguments(self, parser): parser.add_argument('duration') def handle(self, *args, **options): if options['duration'] == 'month': number_of_days = 30 elif options['duration'] == '3month': number_of_days = 90 elif options['duration'] == '6month': number_of_days = 180 else: number_of_days = 30 # self.stdout.write(self.style.SUCCESS('Number of days to delete "%s"' % number_of_days)) today = timezone.now() past_date = today - timedelta(days=number_of_days); # this ensures we don't bother running through already marked true # objects as deleted. to_delete = Package.objects.filter(is_deleted=False, createdAt__lte=past_date) for item in to_delete: item.deleted_at = timezone.now() item.is_deleted = True # this assumes you're doing a soft delete on your model item.save() self.stdout.write(self.style.SUCCESS('Removed "%s"' % to_delete))
Not sure if worth the time to explain what is happening above because the code reads like English already. All Hail Python. You could always leave a question in the comment section below if anything isn’t clear. Happy to help.
Now let’s run the command via cron.
Cron-ify our Command
Please, if you use cron or have used before, yet don’t know of crontab.guru, then happy to introduce to you.
Don’t get stuck playing around on the site. Come back and let’s continue. However I think it is such a cool website for
cron newbies like myself.
To make our
cron command easier to read, let’s create a bash file to house our reference to the django management command. Let’s call it
#!/bin/bash cd /home/your-username/DjangoProject source ./.env/bin/activate python manage.py cleanpackages 3month
./.env/bin/activate assumes that’s where your virtual environment folder is. If you’re using virtualenvwrapper or so, it might be in your virtualenvs folder somewhere. Point to your virtual environment appropriately.
The above commands are nothing new. They are just what we would usually enter into the command line, only this time, they’re packaged into a bash file.
- Change directory to our django project folder
- activate the virtual environment
- then run the management command just like you would
Does it get any simpler than this?
cleanpackages.sh executable via
chmod +x cleanpackages.sh
You can test if your command is right, by simply running a
If all runs fine, then you’re good to go.
Then to our cron.
$ crontab -e
Then let’s add this:
@daily /home/your-username/cleanpackages.sh >> /home/your-username/logs/cleanpackages.log 2>&1 && curl -sm 30 k.wdt.io/<your-email>/<cron-name>?c=@daily
In English, the above is saying:
- Everyday, at 00:00 midnight,
cleanpackages.shwill be run.
- The logs of whatever happened (what you would see in the terminal console) would be pushed into the
- THEN, the beauty of crontab.guru comes in. We make a
curlrequest to an endpoint, which if it works or not, we get an email (or so). No idea if it works or not. Never happened.
On that note, our management command will run every day.
I hope you enjoyed this one. Hope to see you in the next one.
Any questions, don’t hesitate to leave them in the comments.