Django and Relativity

My default Django settings file has changed over time to now include settings that do not depend on the location of the project on the filesystem. This is great in a team environment where more than one person is working on the same project, or when deploying your project to a web server that likely has different paths to the project root directory.

There are essentially 2 places that are looking for a filesystem path:

  1. Templates
  2. Media

Let's assume the following directory structure for a Django project:

.
|-- media
|-- myproject
    |-- __init__.py
    |-- manage.py
    |-- settings.py
    |-- templates
    |   |-- base.html
    |-- urls.py

Project Root

One of the first things in setting up relative filesystem paths for your template and media settings is to determine the root of the project. This can be accomplished easily enough by putting the following lines in your settings.py file:

# settings.py
import os
PROJECT_PATH = os.path.abspath(os.path.split(__file__)[0])

This gets the absolute path using the settings.py file as its source. For example, if the path to your settings file was /www/myproject/settings.py, PROJECT_PATH would be set to /www/myproject. This is exactly what we want as a base for specifying our template and media folders (assuming the above folder structure is what you use).

Templates

Now that we know the root path to our project, let's use that setting to tell Django where our templates are located...

# settings.py
TEMPLATE_DIRS = (
    os.path.join(PROJECT_PATH, 'templates')
)

Continuing our example, this would assume that our template directory is located just inside the root directory of our Django project. It is using os.path's join command to join the path names using the underlying operating system's default directory separator.

Media

In our example, the media folder (which would contain things like images, style sheets, and/or javascript) is a sibling folder of our Django project folder. The way we can specify this relatively from our Django project folder would be, for example, /www/myproject/../media. To accomplish this same thing in our urls.py file would look like the following example:

# urls.py
import os
from django.conf import settings

if settings.DEBUG:
    urlpatterns += patterns('',
        (r'^media/(.*)$', 'django.views.static.serve', {'document_root': os.path.join(settings.PROJECT_PATH, '..', 'media')}),
    )

If settings.MEDIA_URL is set to '/media/', this will match the above pattern and use the built-in generic view to serve the static content. Note that this example also uses a common pattern of only serving media using Django's built-in web server when DEBUG is set to true.

While not shown here, the same can be done for Django's admin media if it happens to be hosted relative to your project. That isn't true in my case -- I have Django's admin media in a shared directory that all of my Django projects can share.

Conclusion

With the above changes, your settings no longer depend on any file system paths that only reside on one particular machine and the project is free to move about without worry of needing to update the settings to specify the correct path -- everything is relative.

Updated 2008-08-12: Updated code snippets to import the os module in its entirety. There's no indication that this conserves memory and it goes against common code practices of importing at the module level.

About this entry

Date Posted:
June 20th 2008 at 3:06:01 PM

Tagged:
django

Previous Entry:
Command Line History

Next Entry:
Using Gmail's SMTP server from Django