The Texas Digital Library has been using the Django framework for a growing number of our smaller projects. Typically, if there’s not already a well established open source solution for the task at hand then the default answer is to write it in Django. Our faculty directory and request systems are already implemented in Django and we are currently refreshing our account management system into the framework. As our use of Django has grown, our practice of storing these projects in the version control repository as one unit has shown its weakness. Within the version control repository, we have passwords, database connections, and file locations stored; in general different settings between production vs development. This makes it hard to keep track of the settings for production vs pre-production and the development instances. This post is my attempt at describe a set of best practices for how to store Django projects in a code repository and deploy them between production and development environments.

Django Applications vs Projects:

Django provides tools and concepts to break up your websites into very small components that can be re-used between sites. The first and most basic distinction that needs to be understood is Django’s difference between applications and projects.
Django Application is a single self-contained set of related features that depends upon the Django framework. By convention, a Django application typically will contain: admin.py, models.py, urls.py, views.py, and other files. These applications should contain no configuration that needs to be changed between installations.
Django Project is a collection of applications that share a single database configuration, work together in a URL space, and share a common set of application configurations. Projects may contain multiple applications or just one. Django requires that projects have at least three files: manage.py, settings.py, and urls.py. I believe it is best to consider Django Projects like Apache’s httpd.conf.

Application Layout

django_application/
    |
    |---------- module_name/
    |              |
    |              |---------- models.py
    |              |
    |              |---------- templates/
    |              |
    |              |---------- urls.py
    |              |
    |              |---------- views.py
    |
    |---------- site_media/
    |              |
    |              |---------- module_name/
    |
    |---------- docs/
The application is where all the code that accomplishes whatever tasks the application requires will reside. It is best to split applications into the smallest possible units to increase the possibility that your application can be reused in another project. As outlined above, there should be three key directories:
  1. a python module,
  2. site_media, and
  3. a directory for any relevant documentation.
The python module will contain all the python source files for your application, this can be easily created using the django-admin.py command ‘startapp‘. Each application should have a set of default templates that reside in a special directory named ‘templates/‘ inside the python module. The default template loaders know to search inside this directory for each applications. The next major directory, ‘site_media/‘, should contain all the static content that is to be served directly from the web server. In order to support the most flexible options during application deployment by local convention, all the files should reside in a sub-directory named the same as the python module. This will make it easier for the web server to separate site media from multiple applications effectively. When building your application make sure that all references to static content take the form of ‘/site_media/module_name/*‘, this way multiple application’s static content can co-exist in the same URL name space.

Project Layout

django_project/
    |
    |---------- manage.py
    |
    |---------- settings.py
    |
    |---------- urls.py
 
Django project should contain only a minimal amount of source code, instead focusing on configuration for the applications. The default layout of projects can be created quickly using the django-admin.py command. These files should be in some sort of version control but they will contain passwords and settings that change between environment that make it difficult to share. This is the same problem any system administrator will face with other configuration files. Locally we use a separate part of our version control repository just for configuration that has limited access set aside just for these types of configuration files.

How to Deploy

Following the patterns outlined here ultimately provides a set of flexible deployment options of your applications and site, avoiding situations where passwords and database connection parameters reside in your source code repository. Each application may have specialized installation instructions. However, the steps outlined below will work for most applications. This assumes that python, django, your database, and apache are already installed.

1) Install the Django Applications

First, check out the desired applications from the code repository and install them into your local python installation. There are three methods you can use:
A) Symlink the python module_name/ directory into python’s site-packages.
(Probably best when actively developing)
B) Run the install script to compile a python egg, and install in site-packages.
(Probably best in a production environment)
C) Modify the pythonpath environmental variable to include the python module.

2) Create a Django project

Use the django-admin.py program to quickly create a new Django project for your site. Using the command will create a default project with all the basic configuration files awaiting your editing.
$ django-admin.py startproject 

3) Customize settings.py

The settings file controls a lot of how your website will work. Below are the four major areas of settings that need to be configured for a particular installation.
A) Database & URL settings
Configure your project to use a particular database. This includes all the DATABASE_* settings for your particular environment. You also need to configure the URL parameters for media.
B) Installed applications
Configure the INSTALLED_APPS array to include the applications desired for your Django project. Because these applications are installed directly as a python site wide package, all you need to do is include the module_name of each application in the array.
C) Application specific settings
Each application will typically contain a set of parameters that need to be configured before it will operate properly. Consult each application’s documentation for specific instructions.

4) Customize urls.py

Django’s urls.py file controls what particular URLs are mapped to specific functions. At the site level you need to map your installed applications into the website’s URL namespace. Some applications may require a particular namespace, and others may require multiple mappings. For a simple basic configuration, add a line for each application as shown below, where URL-NAMESPACE is replaced with the url under which this application should be installed and MODULE-NAME is the application to install.
(r'^URL-NAMESPACE/', include('MODULE-NAME.urls')),
For example, if you want the application ‘myapp‘ to be used for all URLs that begin with ‘myapp‘, then use the following line:
(r'^myapp/', include('myapp.urls')),
As another example, if you want one application (ex: myapp) to be installed at the root of the URL namespace, use the following line:
(r'.', include('myapp.urls')),

5) Setup Apache directives

There is a basic Apache configuration needed for Django to operate properly. Beyond this basic configuration listed below, an additional step is required to enable across to each application’s static content. If your site is using the default templates provided by the application(s), then you need to map each application’s site_media directory so that it is accessible over the web.
Just for reference, this is the basic Django configuration:
SetHandler python-program
PythonHandler django.core.handlers.modpython
SetEnv DJANGO_SETTINGS_MODULE mysite.settings
PythonPath "['/opt/auth/sites'] + sys.path"
Then for each application, map the corresponding location using Apache’s aliases and locations. One possible configuration is:
Alias /site_media/app1 /full/path/to/app1/site_meda/app1

Alias /site_media/app2 /full/path/to/app2/site_media/app2


SetHandler None
Resources:
These ideas are not all my own. I replicated here for only my reference. Here are the resources I used while creating this guide:
  • James Bennett. Practical Django Projects. Apress (June 23, 2008). ISBN 978-1590599969.
    Available from Amazon, Apress, or see a preview on Google Books.