Thursday, June 28, 2007

Django MEDIA_ROOT Deployment Recipe

One problem I have always had with Django is handling different paths between my and other developers development environments and the production environment.

For development purposes, exploiting the fact that settings.py is Python code leads to an adequate solution:

import os
MEDIA_ROOT = '%s/uploads/' % os.getcwd()


So when you do `./manage.py runserver` from the project directory, this variable will reflect any local environment. Unfortunately, if you deploy this app under Apache / mod_python, os.getcwd() does not refer to the project directory like runserver does.

It is trivial to replace the dynamic string with the absolute path to the project on the deployment server, but occasionally I get burned by Subversion either overwriting or finding a conflict with the modified file.

So one day when editing the Apache conf to set up another Django project with mod_python, I had an insight. Now my settings.py looks like this:

import os, posix
PROJECT_ROOT = posix.environ.get('PROJECT_ROOT') or os.getcwd()
MEDIA_ROOT = '%s/uploads/' % PROJECT_ROOT


This works exactly the same as the former solution with runserver. Then for apache in the virtual host configuration, I do this:

<VirtualHost *>
DocumentRoot /home/project/project

ServerName project.com
ServerAdmin noah@project.com

<Directory "/home/project/project">
SetHandler mod_python
PythonHandler django.core.handlers.modpython
PythonPath "['/home/project'] + sys.path"
SetEnv DJANGO_SETTINGS_MODULE project.settings
SetEnv PROJECT_ROOT "/home/project/project"
</Directory>

LogLevel warn
CustomLog /home/project/log/access.log combined
ErrorLog /home/project/log/error.log
</VirtualHost>


This line does the magic:

SetEnv PROJECT_ROOT "/home/project/project"


This moves the deployment server-specific configuration outside of my Django project and into Apache.

1 comment:

LET'S GO TO THE BITHC! said...

What about a more general
MEDIA_ROOT = os.path.join( sys.path[0], 'media' )
?

os.path.join(os.path.dirname(__file__), 'media') might be another option.