Monday, June 01, 2009

Running External Django Scripts

Django is pretty good at creating a database driven website. The documentation is clear and the tutorials show how to use the framework to create web based applications. But one part that I wish was a bit more straight forward is running scripts outside the web server. The issue is that Django code expects to have a certain environment configured and setup for the framework. With this in place, you can preform tasks like polling an IMAP server for incoming email messages or monitoring a directory for new files or whatever else needs to be done. There are several posts online to help you get the environment setup here, here and here. But some of them seem not to work correctly because of the changes to Django for the 1.0 release or other reasons.

I have a fairly straight forward example of how to setup the Django environment and allow the rest of your code to access the Django framework for your web application. Its remarkably simple and straight forward.

Suppose that I've created a Django project in my tmp directory called demo_scripts and within that project, I create an app called someapp.

peter@fog:~/tmp> django-admin-2.5.py startproject demo_scripts
peter@fog:~/tmp> cd demo_scripts/
peter@fog:~/tmp/demo_scripts> django-admin-2.5.py startapp someapp
peter@fog:~/tmp/demo_scripts>


I create a model in someapp that looks like:

from django.db import models

class Foo(models.Model):
name = models.CharField(max_length=21,
unique=True,
help_text="Name of the foo.")

def __unicode__(self):
return self.name

class Meta:
ordering = ('name',)


Next step is to sync the database:

peter@fog:~/tmp/demo_scripts> ./manage.py syncdb
Creating table auth_permission
Creating table auth_group
Creating table auth_user
Creating table auth_message
Creating table django_content_type
Creating table django_session
Creating table django_site
Creating table someapp_foo

You just installed Django's auth system, which means you don't have any superusers defined.
Would you like to create one now? (yes/no): yes
Username (Leave blank to use 'peter'):
E-mail address: pkropf@gmail.com
Password:
Password (again):
Superuser created successfully.
Installing index for auth.Permission model
Installing index for auth.Message model
peter@fog:~/tmp/demo_scripts>


And add some initial data to the database:

peter@fog:~/tmp/demo_scripts> ./manage.py shell
Python 2.5.4 (r254:67916, May 1 2009, 17:14:50)
[GCC 4.0.1 (Apple Inc. build 5490)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from someapp.models import Foo
>>> Foo(name='A Foo').save()
>>> Foo(name='Another Foo').save()
>>>
peter@fog:~/tmp/demo_scripts>


Now we can write a standalone script to do something with the data model. For simplicity's sake, I'll just print out all the Foo objects. The script is going to live in a new directory called scripts. Here's the source:

#! /usr/bin/env python
#coding:utf-8

import sys
import os
import datetime

sys.path.insert(0, os.path.expanduser('~/tmp/demo_scripts'))
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'

from someapp.models import *
print Foo.objects.all()


When I run the script, it prints the array of the two Foo objects that I previously created:

peter@fog:~/tmp/demo_scripts> ./scripts/show_foo.py 
[<Foo: A Foo>, <Foo: Another Foo>]
peter@fog:~/tmp/demo_scripts>


Lines 8 and 9 are the critical lines in the script code. The first adds the project directory to the Python system path so that the settings module can be found. The second tells the Django code which module to import to determine the project settings.

No comments: