Jan 19, 2012

How to use django_extensions' runscript command

The django_extensions app provides many helpful additions for the Django developer, which are worth checking out. I highly recommend it to anyone working on a Django project. One such addition is runscript, which allows you to run any script in the Django context, without having to manually import and configure your paths and Django settings. Unfortunately, there is very little documentation on how to correctly use it. This blog post here just quickly sums it all up:

1. Running a script

This is done like this:

    ./manage.py runscript <scriptname>

You cannot specify the name of a specific Python file, though. Scripts have to be within modules in a particular location, which is explained next.

2. The location of scripts

The runscript command looks for modules called scripts. These modules may be located in your project root directory, but may also reside in any of your apps directories. This allows you to maintain app-specific scripts. So, create the scripts directory (either at the root or within an apps directory), along with an __init__.py file:

    mkdir scripts
    touch scripts/__init__.py

3. The script itself

Scripts are simple Python files, but they need to contain a run() function. For example like this:

    def run():
        print "I am a script"

Within such a script, you could import and use any of your models or other parts of your Django project. When you store the above code in a file called scripts/testscript.py then you can run it like so (note that this is without the .py extension):

    ./manage.py runscript testscript

4. Run multiple scripts at once

A nice feature of runscript  is that you can execute multiple scripts at the same time, if those scripts have the same name. Assume that you have different applications and wish to initialize data for them by running a script. Rather than putting all of this into a single script, you could have a scripts directory in your various apps directories, and within each of those have - for example - an init_data.py script, thus keeping each script smaller and easier to understand and maintain.

You can see this in action if you specify more verbose output via the "-v 2" option. 

    ./manage.py runscript -v 2 init_data

The output will look something like this:

    Check for django_extensions.scripts.init_data
    Check for django.contrib.auth.scripts.init_data
    ...
    Check for one_of_my_apps.scripts.init_data
    Found script 'one_of_my_apps.scripts.init_data' ...
    Running script 'one_of_my_apps.scripts.init_data' ...
    I am a script for one of my apps.
    Check for some_other_app.scripts.init_data
    Found script 'some_other_app.scripts.init_data' ...
    Running script 'some_other_app.scripts.init_data' ...
    I am a script for some other app.
    Check for scripts.init_data
    Found script 'scripts.init_data' ...
    Running script 'scripts.init_data' ...
    I am a script at the root level.

As you can see, runscript checks for a scripts module for every installed application, plus on the root level. If it finds a match, it runs the script and then keeps looking for more matches.


2 comments:

  1. This is great. Can you pass variables into runscript?

    ReplyDelete
  2. You can pass variables in through the command prompt.

    Your python code:

    def run(*args):
    print args


    ------------------
    On the command line you should type:

    python manage.py --script-args=whatever

    ReplyDelete