When developing projects with Django, one usually uses at least two deployments of the project: One for developing things and another for the production site.
Let’s assume that the development deployment resides on your local computer in the directory /www/project and can be accessed via http://localhost:8000/. The production site uses Apache and mod_python, is available at http://project.tld/, and lives in /var/www/sites/project.
In such a situation it is common to have different Django settings files for each deployment — it’s safe to assume that paths on your local machine are different than paths on the production server, that another database (think of SQLite on the development host and MySQL in production) or at least other access credentials are used, and so on.
I found that implementing the above requirements in an easy to reproduce and convenient manner in Django is everything but trivial (at least for me), which is why I decided to write up how I did it.
Step 1: Make sure Django is installed properly
By properly installed I mean that Python knows where the Django packages are. Fire up an instance of the Python interpreter interface by invoking the command python on your shell.
localhost:~$ python
Python 2.5.2 (r252:60911, Sep 22 2008, 14:42:43)
[GCC 4.0.1 (Apple Computer, Inc. build 5250)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import django
>>>
No error means: Good.
(You might have noticed that I’m using OS X here. This does not really matter because the ideas and concepts presented below work on any other UNIX flavor as well. They should work on Windows as well.)
Step 2: Development deployment setup
On the development machine I want to use the development server that ships with Django. It’s easy to use, light-weight and, in contrast to Apache, automatically reloads Python code for each request, which is very convenient for development. (Speaking of which, I have never understood why Python does not automatically
notice that code changed in the Apache deployment. Come on people, other scripting languages have been supporting this ever since.)
The Django settings file for the development setup resides in /www/project/settings/development.py:
localhost:/www/project $ ls -1 settings/
__init__.py
development.py
Django itself places the settings file in /www/project/settings.py when creating the project. When moving it to a subdirectory, make sure to create an empty __init__.py in there. In my case, I did exactly this and removed the default settings.py file.
Now when you try to run the development server, it actually looks like something might work:
localhost:/www/project.tld $ python manage.py runserver
Validating models...
0 errors found
Django version 1.0-final-SVN-unknown, using settings 'settings.__init__'
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
As you can see, Django thinks that the settings can be found in settings/__init__.py. When retrieving http://localhost:8000, you’ll see that this totally does not work. Who would have thought?
When attempting to start the server using django-admin.py, things get even worse:
localhost:/www/project $ django-admin.py runserver
Error: Settings cannot be imported, because environment variable
DJANGO_SETTINGS_MODULE is undefined.
At the same time, this gives us a valuable hint: The DJANGO_SETTINGS_MODULE environment variable can be used to point Django to the settings file that should be used:
localhost:/www/project $ export DJANGO_SETTINGS_MODULE=project.settings.development
localhost:/www/project $ django-admin.py runserver
Error: Could not import settings 'project.settings.development' (Is it on sys.path?
Does it have syntax errors?): No module named project.settings.development
Still no luck, but a different error message this time. The problem now is that Python has no idea from where to load the file. It uses some predefined directories in the sys.path variable to search in when interpreting import statements, but none of them contains settings/development.py. This can be easily solved by setting the environment variable PYTHONPATH to the parent directory of our project, i.e. /www:
localhost:/www/project $ export PYTHONPATH=/www
localhost:/www/project $ export DJANGO_SETTINGS_MODULE=project.settings.development
localhost:/www/project $ django-admin.py runserver
Validating models...
0 errors found
Django version 1.0-final-SVN-unknown, using settings 'project.settings.development'
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
There you go: Now the development server is using the correct settings file. In the next section the Apache setup for the production site is explain.
Update: I received an email from someone who told me that, after settings PYTHONPATH to /www, django-admin.py claimed it could not find the django.core package anymore. The problem could be solved for him by setting PYTHONPATH to /directory/to/django:/www. I cannot reproduce this with my setup though.
Step 3: Production deployment setup
With the findings from the previous section, configuring Apache and mod_python is a lot easier than one might think. Basically the same tasks as earlier for the development server need to be done: First tell Apache which configuration file should be used. For the production setup this is settings/production.py. Then tell Apache where to look for production.py. Earlier this was done via the PYTHONPATH environment variable — mod_python employs a similar mechanism:
<VirtualHost *:80>
DocumentRoot /var/www/sites/project
ServerName project.tld
<Location />
SetHandler python-program
PythonHandler django.core.handlers.modpython
SetEnv DJANGO_SETTINGS_MODULE project.settings.production
PythonPath "['/var/www/sites'] + sys.path"
</Location>
</VirtualHost>
The SetEnv command populates the DJANGO_SETTINGS_MODULE variable within Apache and makes it point to production.py. The PythonPath directive tells Apache in which directories to search for packages and files.