发布时间:2022-08-09 文章分类:编程知识 投稿人:赵颖 字号: 默认 | | 超大 打印

http://stackoverflow.com/questions/3200001/using-crontab-with-django

Kronos

Kronos makes it really easy to schedule tasks with cron.

Usage

Define tasks

Kronos collects tasks from cron modules in your project root and each of your applications:

# app/cron.py
import kronos
@kronos.register('0 0 * * *')
def complain():
    complaints = [
        "I forgot to migrate our applications's cron jobs to our new server! Darn!",
        "I'm out of complaints! Damnit!"
    ]
    print random.choice(complaints)

Run tasks manually

$ python manage.py runtask complain
I forgot to migrate our applications's cron jobs to our new server! Darn!

Register tasks with cron

$ python manage.py installtasks
Installed 1 task.

Installation

$ pip install django-kronos

... and add kronos to INSTALLED_APPS.

Contribute

I love you

Johannes Gorset made this. You should tweet me if you can't get it
to work. In fact, you should tweet me anyway.

Creating a Django cron job

Sunday, September 17, 2006

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!

About the Author

Gerald Kaszuba

You can follow me on Google+, Twitter (@gakman) or contact me directly on email. More information about me, my projects and my résumé can be found on geraldkaszuba.com.

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)
#!/usr/bin/env python
from mytestapp.views import daily_job
daily_job()

EnvironmentError: Environment variable DJANGO_SETTINGS_MODULE is undefined.

#!/usr/bin/env python
import os
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
from mytestapp.views import daily_job
daily_job()
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))
python run.py mytestapp.views daily_job()
0 0 * * * python /path/to/mytestproject/run.py mytestapp.views daily_job()

Chronograph

Control django-admin commands via the web.

Creating cron jobs for Django apps can be a pain, annoying and repetitive. With
django-chronograph you simply create a single cron job to run every minute,
point it at your site's directory and run manage.py cron. Then from the admin
you can add jobs.

Note

django-chronograph supports Django 1.1+.

Installation and Usage

Read docs/overview.txt for more information, build the documentation with
Sphinx or view them online here.

You can also grab the latest release from PyPI:

pip install django-chronograph

Scheduled Tasks (or cron jobs) with Django

This is my take on setting up cron jobs for the apps in a Django project. It is based on my own convention, and it solves my initial problems where I want to perform some action on all of my Django apps at a periodic interval (currently this is a once-a-day task).

In order for this to work, I create a cron.py module for all of my INSTALLED_APPS. This module must contain a run method. Other than that, it can work just like any other python module (using django's internals as necessary).

For example, if you had an app called utils (possibly located at mysite/utils/), and if you just wanted to delete all sessions with old expire_dates, your cron.py (which you would put in mysite/utils/cron.py) might look something like this:

from datetime import datetime
from django.contrib.sessions.models import Session
def delete_old_sessions():
    Session.objects.filter(expire_date__lt=datetime.now()).delete()
def run():
    delete_old_sessions()

Now, the meat of this solution checks for the cron.py module in all of the apps in mysite.settings.INSTALLED_APPS, and invokes its run() method. I've also named this module cron.py, but this gets stored in Django's project directory (e.g. mysite)... the same directory where your settings.py is located.

#!/usr/bin/env python
"""
Project-wide Cron Job... A Command-line Django Script.

This script gets scheduled and run by cron (or whatever).
It then calls the `run` method of each app's cron module, 
if it exists (should be `appname/cron.py`)

This script should be invoked after setting the 
DJANGO_SETTINGS_MODULE environment variable.

You chould do this in a BASH script as follows:
    export DJANGO_SETTINGS_MODULE=mysite.settings
    python /path/to/mysite/cron.py
"""
from django.conf import settings
def my_import(name):
    '''
    __import__ helper function to import modules inside packages
    e.g.:  where name is something like 'package.module.mod_i_want',
           would return mod_i_want

    See: http://www.python.org/doc/2.5.2/lib/built-in-funcs.html
    '''
    mod = __import__(name)
    components = name.split('.')
    for comp in components[1:]:
        mod = getattr(mod, comp)
    return mod
def run():
    for app in settings.INSTALLED_APPS:
        if not app.startswith('django'):
            output_info = '%s.cron'%app
            ## Dynamically import a module called 'cron'
            ## from each INSTALLED_APP (if it exists)
            try:
                cron_mod = my_import(app+'.cron')
                output_info += '... FOUND'
                print output_info
                ## 3. Execute the cron's run method (if it exists)
                if hasattr(cron_mod, 'run'):
                    #print '---> calling run()'
                    cron_mod.run()
            except ImportError:
                # ignore packages that don't have a cron module
                output_info += '... SKIPPED'
                print output_info
if __name__ == "__main__":
    run()

The final piece of this puzzle lies in the BASH script used to invoke the above python module. It makes sure the appropriate environment variables are set and then it invokes the above module. I also store this in my django project directory (as cron.sh), and I use cron to schedule it to run.

#!/bin/bash
# This is a Django, Project-specific Cron script.
# Separate Projects would need a copy of this script 
# with appropriate Settings export statments.

PYTHONPATH="${PYTHONPATH}:/path/to/django/project/directory"
export PYTHONPATH
export DJANGO_SETTINGS_MODULE=mysite.settings
python/path/to/django/project/directory/mysite/cron.py

Using cron, you'd schudule this to run every morning at 6am by editing your crontab and adding the following:

#m h  dom mon dow   command
  0   6    *        *      *     /path/to/django/project/directory/cron.sh

That's it. This has been working for me, but there is at least one major pitfall: All of your app's cron tasks get run at the same time. This works well if your apps need to do something once a day (which has been my requirement), but this probably won't work well if you have some apps that need to run tasks at differing times.

There are also other solutions to this (none of which I've tried). There's a snippet at http://www.djangosnippets.org/snippets/1126/ which looks interesting. Then there's the django-cron app which seems to be fairly flexible in how it works, and it doesn't require cron (so this is a plus if you cant set a crontab or if you're on Windows!)

Thanks in advance for any feedback... suggestions are always welcome!