Django’s development server is capable of serving static (media) files thanks to the view django.views.static.serve. Popular web servers like Apache, Lighttpd or NGINX are much faster though, and as such should be used in production mode. Our goal is to bypass Django and let Apache (or other valid alternatives) directly serve static files like images, videos, CSS, JavaScript files, and so on, for us.
Generally speaking, for performance reasons, it’s advised that you have two different webservers serving your dynamic requests and static files. In practice, for smaller sites, people often opt to simply use one webserver. In this article, I’ll discuss how to serve the static files within your Django project, through Apache.
The first thing we need to do is distinguish between development and production mode. We can do so by simply specifying DEBUG = True (development), or DEBUG = False (production) within our settings.py file.
settings.py may include (among others) the following declarations:
# Absolute path to the project directory
BASE_PATH = os.path.dirname(os.path.abspath(__file__))
# Main URL for the project
BASE_URL = 'https://example.org'
DEBUG = False
# Absolute path to the directory that holds media
MEDIA_ROOT = '%s/media/' % BASE_PATH
# URL that handles the media served from MEDIA_ROOT
MEDIA_URL = '%s/site_media/' % BASE_URL
# URL prefix for admin media -- CSS, JavaScript and images.
ADMIN_MEDIA_PREFIX = "%sadmin/" % MEDIA_URL
*PATH constants indicate paths on your filesystem (e.g., /home/myuser/projects/myproject), while *URL constants indicate the actual URL needed to reach a given page or file.
Notice that it’s not unusual to have a /site_media URL that corresponds to a /media folder. In the example above, I opted to separate regular media files for the project from the standard ones that ship with Django for the admin section. To do this, all we have to do is create a symbolic link as follows:
ln -s /usr/lib/python2.5/site-packages/django/contrib/admin/media /path/to/myproject/media/admin
When you’re in development mode, and DEBUG = True, you want to let Django serve your static files. This can be done by adding the following snippet (or similar) to your urls.py:
if settings.DEBUG:
urlpatterns += patterns('',
(r'^site_media/(?P<path>.*)$', 'django.views.static.serve', {'document_root': settings.MEDIA_ROOT}),
)
In production mode, the code contained within the if clause will not be executed as we’ve set DEBUG to False within settings.py.
From the Django side of things, we are good. We now need to instruct Apache. Within your virtual host file, you can specify something along the lines of:
<VirtualHost *:80>
#...
SetHandler python-program
PythonHandler django.core.handlers.modpython
SetEnv DJANGO_SETTINGS_MODULE myproject.settings
PythonDebug On
PythonAutoReload Off
PythonPath "['/usr/lib/python2.5/site-packages/django', '/path/to/myproject'] + sys.path"
#...
Alias /site_media "/path/to/myproject/media"
<Location "/site_media">
SetHandler None
</Location>
</VirtualHost>
The first group of declarations essentially tells Apache to use mod_python to handle any incoming requests. However, we don’t want Django to deal with static files, so the second group of declarations, aliases/maps the /site_media URL with the actual media directory on the server, and tells Apache to threat it as static content (with SetHandler None) bypassing de facto Django.
Leave a Reply