One of the most common questions that comes up in #django is about static files.
Why are my images not loading? How do I make Django serve my CSS files? The
answer depends on the environment. You might want to hook up django.views.static.serve
in development and Alias in production. I want to help clarify all static
file questions.
How do I make Django serve static files?
It is possible to setup Django to serve your static files. This functionality is off by default. Django is a web application framework. It is not intended to serve any static files. It might serve static content which is cached in memcached, the database or on the filesystem. The method to setup static file serving in Django is disclaimed in the documentation:
Using this method is inefficient and insecure. Do not use this in a production setting. Use this only for development.
Check out the static documentation for Django to get more information about
how to set it up with your urls.py. Lets cover what settings that Django has
that I will use through out the rest of this article:
MEDIA_ROOT- The default value is
""(an empty string). Django usesMEDIA_ROOTas the root path for theupload_toparameter forFileFieldandImageField. It is typically the place where you will want to make publically available through your web server. MEDIA_URL- The default value is
""(an empty string). There is nothing magically aboutMEDIA_URL. It is more of an aide to you to properly map static files to the correct location in your templates. You can getMEDIA_URLdefined in all of your templates by usingdjango.core.context_processors.mediain yourTEMPLATE_CONTEXT_PROCESSORS. This is turned on by default if you are using SVN revision 5379 or newer. However, you need to ensure you are using theRequestContextas your context in reach view that renders a template.
A quick tip serving static files in development
I can't say that I invented this idea, because I originally found it in
Satchmo. Create a new settings variable called LOCAL_DEVELOPMENT. Set the
value to either True or False depending on whether the project is local
or on a production server. Then make your urls.py look similar to this:
from django.conf import settings
from django.conf.urls.defaults import *
urlpatterns = patterns("",
# normal url patterns here.
)
if settings.LOCAL_DEVELOPMENT:
urlpatterns += patterns("django.views",
url(r"%s(?P<path>.*)/$" % settings.MEDIA_URL[1:], "static.serve", {
"document_root": settings.MEDIA_ROOT,
})
)
Keep in mind that if you have a url pattern that consumes your MEDIA_URL
before getting to the new one I show you above then you will need to restructure
things. Also keep in mind that if your MEDIA_URL is an absolute URL then
this will clearly not work. If you have separated your settings.py file to
allow for different settings in different locations then just override your main
MEDIA_URL to be something that can be used in the urlpatterns.
UPDATE: It has come to my attension that the above code was wrong and has
now been corrected. It used to allow settings.MEDIA_URL pass through to
the regex, but that was incorrect when settings.MEDIA_URL has a leading
slash as it should to be properly referenced in the templates. I am now using
settings.MEDIA_URL[1:] to eat the leading slash.
Serving static files in production
I will describe how to accomplish static file serving using Apache. This is the easiest method to configure considering you are probably deploying to Apache. Here is a quick example of how you might setup Django within Apache and mod_python:
<Location "/">
SetHandler python-program
PythonHandler django.core.handlers.modpython
SetEnv DJANGO_SETTINGS_MODULE mysite.settings
PythonDebug On
</Location>
This works well, but as you can see if a request is made to
/site_media/css/layout.css then it is passed to Django. Then Django would
need to resolve it and return something back to client. If you accidently left
LOCAL_DEVELOPMENT turned on then this will magically work and you may ignore
that and assume everything is okay. However, this is very bad because now Django
is being forced to serve static files when the web server should be responsible
for that. Apache can serve the static files much more efficiently than Django
can. So, let's add on to our Apache configuration:
<Location "/site_media">
SetHandler None
</Location>
Okay, now we have told Apache that when a request is made with /site_media
as the beginning portion of the path to do nothing. We are not done yet, because
we need to tell Apache to map requests from /site_media to the files located
on the file system. This can be done using Apache's Alias directive:
Alias /site_media/ /path/to/media
<Location "/site_media">
SetHandler None
</Location>
Replace /path/to/media to your MEDIA_ROOT path. Setting up the admin
media files is done the same way. Just map ADMIN_MEDIA_PREFIX to the location
of the admin media files. The location will vary from system to system, but the
path inside the Django source tree is django/contrib/admin/media. Be sure
to find out where your Django source tree resides and map it accordingly. Also,
keep in mind you may need to look at the permissions to ensure the webserver user
that Apache runs as has the permission to read those files. This applies to all
static files being served by Apache.
This wraps up how to serve static files in a Django environment. I am looking forward to expand on this article and cover Cherokee and the environment that is required for that setup.

Excellent post and thank you for detailing this. It comes up so often and now this is a great resource to point people to.
I do have a question, why is it that you use LOCAL_DEVELOPMENT as opposed to just using DEBUG like the docs show? You mentioned this on the show and I didn't get to clarify it then.
Thanks again.
Posted by Empty on Jan 24, 2008 at 6:54 PM