Django|Static Files
Django and Static Files
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_ROOT
as the root path for theupload_to
parameter forFileField
andImageField
. 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_URL
defined in all of your templates by usingdjango.core.context_processors.media
in 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 theRequestContext
as 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.
No comments:
Post a Comment