Serving media à la WSGI

Until now, the most common approach to serving static files (aka “media”) in Django is to serve it from your application if you’re running the development server (i.e., by adding an entry to a URLConf with a built-in view), and let the Web server do it in deployment.

The main disadvantage of this approach is that the development environment becomes less similar to what you will have in production. If you’re not going to be serving static files on the final site, why serve them in the development machines?

To work around this, you can have a WSGI application serving your media, so your application will only serve your own views, just like you’d do in production. There are some WSGI applications out there that serve static files which you can take and configure, but twod.wsgi has a function to configure one of them (paste.urlparser.StaticURLParser) based on your MEDIA_ROOT and MEDIA_URL settings.

Using it is very easy, absolutely reliable and compatible with anything you may have now. And it’s also able to serve the media for Django Admin. It will always call your application, unless the requested path begins with MEDIA_URL or ADMIN_MEDIA_PREFIX.

This is something optional. When used under a multi-threaded server like PasteScript, it should be even faster given that nothing from Django gets run while serving the static files.

Configuring it from a PasteDeploy file will always take 3 additional lines:

# ...

[composite:full_app]
use = egg:twod.wsgi#full_django
django_app = myapp

# ...

django_app represents your Django application, which can be:

  • The name of an app: section in the same configuration file, where this application is configured.
  • The URI to an application in another PasteDeploy configuration file (e.g., “config:/path/to/config.ini”, “config:/path/to/config.ini#develop”).
  • The URI to an entry point for a PasteDeploy application factory (e.g., “egg:yourpackage#entry_point”).

You’ll then need to make sure you load full_app instead of myapp, since the latter is presumably no longer able to serve media. To that end, you may consider renaming composite:full_app to composite:main.

Setting up the media programatically

If for some reason you need to set this up from your Python code, you can use the twod.wsgi.factories.add_media_to_app() function:

from paste.deploy import loadapp
from twod.wsgi.factories import add_media_to_app

# The Django-powered application, with no media:
django_app = loadapp("config:/path/to/config.ini")

# The Django-powered application plus the media:
full_app = add_media_to_app(django_app)

This would be particularly useful if you’d like to serve static files from more than one directory:

from paste.urlparser import StaticURLParser

full_app['/css'] = StaticURLParser("/path/to/the/css/directory")
full_app['/js'] = StaticURLParser("/path/to/the/js/directory")

Of course, this would be something you’d do on your development servers. In production environments it’s always best to leave the server serve the static files.