Managing static files for Django applications

Update, 1 Apr 2011: The issue of managing static files has been solved in Django 1.3.

Two principles of Django development lead to a dilemma:

  1. Application code should be self-contained — i.e., not coupled with a project.
  2. Django should not serve static media files (for security and efficiency).

So, how does one manage static files (images, css, js, etc.) that are bundled with an application?  I make a couple of assumptions:

  1. You don’t want to hard-code full URL paths in templates, so you need some way to inject a base URL dynamically into your template context.
  2. You want to keep the media files in the application package — that is, not to copy or move them to a filesystem location outside the application directory.

Django’s builtin settings provide for two non-admin media settings, MEDIA_ROOT and MEDIA_URL.  One option for resolving the issue is to use MEDIA_URL and create symlinks from the MEDIA_ROOT directory to the application’s media directory (or directories).  Personally, I don’t like that, partly because I prefer not to use symlinks, but mostly because the MEDIA_ROOT space is used for uploads for model file fields, and it feels like this other static, presentation-related, content should be in its own space.  OTOH the symlink approach is probably the most flexible.

What I’ve been doing to this point is based on the assumption that my application packages all live in the same base directory. I added a custom setting APP_MEDIA_PREFIX (inspired by ADMIN_MEDIA_PREFIX) and set it to the URL path which I alias in in Apache.

Django setting:

APP_MEDIA_PREFIX = '/django/apps/'

Apache conf:

# Application media
AliasMatch ^/django/apps/([^/]+)/media/(.+) /opt/django/apps/$1/media/$2
<DirectoryMatch "^/opt/django/apps/[^/]+/media">
    Allow from all
</DirectoryMatch>

My apps packages are in /opt/django/apps and by convention put their media files in a “media” subdirectory. Then I created a custom template tag for printing APP_MEDIA_PREFIX (inspired by {% admin_media_prefix %}) in my custom template tag module (custom.py):

from django import template
from django.conf import settings

register = template.Library()

@register.simple_tag
def app_media_prefix():
    """Prints value of APP_MEDIA_PREFIX setting.

    Usage: {% app_media_prefix %}
    """
    return getattr(settings, 'APP_MEDIA_PREFIX', '')

Then, in a template, for example:

{% load custom %}
<link rel="stylesheet" type="text/css" href="{% app_media_prefix %}locationguide/media/css/locationguide.css"/>

In this case, the application name/label is “locationguide” and is located in /opt/django/apps/locationguide.

If anyone has thought of a significantly better way to manage this scenario, I’d love to hear it.

Advertisements

, ,

  1. #1 by Erik Allik on January 29, 2009 - 6:09 pm

    What about those reusable apps that do not follow this convention, i.e. those that have been written by someone else?

  2. #2 by David Chandek-Stark on January 30, 2009 - 10:56 am

    Well, it won’t cause a problem, if that’s what you mean. If a third-part app ships with templates and static media files, chances are you’re going to have to tweak them anyway to fit your environment. James Bennett makes this point in his DjangoCon talk on reusable apps.