Creating a Django cron job

I couldn’t find a way to directly call a Python function in a Django application view from the command line. It doesn’t seem like it is a common thing to do from my Google search attempts. In this example I have a function defined to download a few web sites once a day using a custom made Django model. The project is called mytestproject and the application is called mytestapp. Here is the views.py file:

import urllib2
from models import WebSite
def daily_job():
    for site in WebSite.objects.all():
        page_html = urllib2.urlopen(site.url).read()
        do_something_with_page_html(page_html)

To run this function from the command line an optimist would create a python script that looks like this:

#!/usr/bin/env python
from mytestapp.views import daily_job
daily_job()

Running this will give you an exception about your DJANGO_SETTINGS_MODULE environment variable not being defined:

EnvironmentError: Environment variable DJANGO_SETTINGS_MODULE is undefined.

Lets change the script a little to conform with Django’s demands.

#!/usr/bin/env python
import os
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
from mytestapp.views import daily_job
daily_job()

Please note that according to the documentation, DJANGO_SETTINGS_MODULE should be ‘mytestproject.settings’ instead of just ‘settings’. Using the project name in DJANGO_SETTINGS_MODULE will cause troubles in our situation because Django does some tricky things to your path before importing the settings module. For our needs it isn’t necessary to do this.

Of course you can make this script a little more generic so you can run an arbitrary script from your cron job if you feel the need to:

import sys
import os

os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'

module_name = sys.argv[1]
function_name = ' '.join(sys.argv[2:])

exec('import %s' % module_name)
exec('%s.%s' % (module_name, function_name))

I’ll call this script run.py. To run my daily_job function:

python run.py mytestapp.views daily_job()

And your modnight cron job entry should look something like:

0 0 * * * python /path/to/mytestproject/run.py mytestapp.views daily_job()

And there you have it. I hope this will save you some time!

10 thoughts on “Creating a Django cron job”

  1. If a module_name is not a “top-level” module you’ll need to use the following hack:

    module = __import__(module_name, globals(), locals(), [”])
    getattr(module, function_name)()

  2. I’ve tried following the steps outlined here and am getting an error. If I set os.environ[‘DJANGO_SETTINGS_MODULE’] = ‘settings’, I get the error:
    ImportError: No module named mytestproject

    I’ve also tried with mytestproject.settings and get:
    EnvironmentError: Could not import settings ‘mytestproject.settings’ (Is it on sys.path? Does it have syntax errors?): No module named mytestproject.settings

    I’m curious if I’m missing something obvious such as where the python script should go? I put my script in the same folder as settings.py. Is that correct?

  3. Heh, fixed the problem almost immediately after asking for help. Isn’t that always the way? I just added:
    sys.path.append(“../”)
    That way the import worked fine. Perhaps this will be helpful to someone.

  4. It can also be really helpful to manually set the python path in the script itself, rather than relying on it being set in the environment. All of my scripts that interact with Django start with something like:

    #################### Set up Django environment
    import sys,os

    sys.path.append(‘/home/crest/sites/lib’)
    sys.path.append(‘/home/crest/sites/projects’)

    os.environ[‘DJANGO_SETTINGS_MODULE’] =’ourcrestmont.settings’

    from django.core.management import setup_environ
    from ourcrestmont import settings
    setup_environ(settings)

  5. Thanks. Dropping the project name was the bit I was missing. I’ve been trying to figure this out for the last several hours. Thank you for posting this!

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>