Django developers mostly concern themselves with the dynamic parts of web applications – the views and templates that render anew for each request. But web applications have other parts: the static files (images, CSS, Javascript, etc.) that are needed to render a complete web page.
For small projects, this isn’t a big deal, because you can just keep the static files somewhere your web server can find it. However, in bigger projects – especially those comprised of multiple apps – dealing with the multiple sets of static files provided by each application starts to get tricky.
That’s what django.contrib.staticfiles is for: it collects static files from each of your applications (and any other places you specify) into a single location that can easily be served in production.
Note
If you’ve used the django-staticfiles third-party app before, then django.contrib.staticfiles will look very familiar. That’s because they’re essentially the same code: django.contrib.staticfiles started its life as django-staticfiles and was merged into Django 1.3.
If you’re upgrading from django-staticfiles, please see Upgrading from django-staticfiles, below, for a few minor changes you’ll need to make.
Put your static files somewhere that staticfiles will find them.
By default, this means within static/ subdirectories of apps in your INSTALLED_APPS.
Your project will probably also have static assets that aren’t tied to a particular app. The STATICFILES_DIRS setting is a tuple of filesystem directories to check when loading static files. It’s a search path that is by default empty. See the STATICFILES_DIRS docs how to extend this list of additional paths.
Additionally, see the documentation for the STATICFILES_FINDERS setting for details on how staticfiles finds your files.
Make sure that django.contrib.staticfiles is included in your INSTALLED_APPS.
For local development, if you are using runserver or adding staticfiles_urlpatterns to your URLconf, you’re done with the setup – your static files will automatically be served at the default (for newly created projects) STATIC_URL of /static/.
You’ll probably need to refer to these files in your templates. The easiest method is to use the included context processor which allows template code like:
<img src="{{ STATIC_URL }}images/hi.jpg" />
See Referring to static files in templates for more details, including an alternate method using a template tag.
When you're ready to move out of local development and deploy your project:
Set the STATIC_URL setting to the public URL for your static files (in most cases, the default value of /static/ is just fine).
Set the STATIC_ROOT setting to point to the filesystem path you'd like your static files collected to when you use the collectstatic management command. For example:
STATIC_ROOT = "/home/jacob/projects/mysite.com/sitestatic"
Run the collectstatic management command:
./manage.py collectstatic
This'll churn through your static file storage and copy them into the directory given by STATIC_ROOT.
Deploy those files by configuring your webserver of choice to serve the files in STATIC_ROOT at STATIC_URL.
Serving static files in production covers some common deployment strategies for static files.
Those are the basics. For more details on common configuration options, read on; for a detailed reference of the settings, commands, and other bits included with the framework see the staticfiles reference.
Note
In previous versions of Django, it was common to place static assets in MEDIA_ROOT along with user-uploaded files, and serve them both at MEDIA_URL. Part of the purpose of introducing the staticfiles app is to make it easier to keep static files separate from user-uploaded files.
For this reason, you need to make your MEDIA_ROOT and MEDIA_URL different from your STATIC_ROOT and STATIC_URL. You will need to arrange for serving of files in MEDIA_ROOT yourself; staticfiles does not deal with user-uploaded files at all. You can, however, use django.views.static.serve() view for serving MEDIA_ROOT in development; see Serving other directories.
At some point, you'll probably need to link to static files in your templates. You could, of course, simply hardcode the path to you assets in the templates:
<img src="http://static.example.com/static/myimage.jpg" />
Of course, there are some serious problems with this: it doesn't work well in development, and it makes it very hard to change where you've deployed your static files. If, for example, you wanted to switch to using a content delivery network (CDN), then you'd need to change more or less every single template.
A far better way is to use the value of the STATIC_URL setting directly in your templates. This means that a switch of static files servers only requires changing that single value. Much better!
Django includes multiple built-in ways of using this setting in your templates: a context processor and a template tag.
The included context processor is the easy way. Simply make sure 'django.core.context_processors.static' is in your TEMPLATE_CONTEXT_PROCESSORS. It's there by default, and if you're editing that setting by hand it should look something like:
TEMPLATE_CONTEXT_PROCESSORS = (
'django.core.context_processors.debug',
'django.core.context_processors.i18n',
'django.core.context_processors.media',
'django.core.context_processors.static',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
)
Once that's done, you can refer to STATIC_URL in your templates:
<img src="{{ STATIC_URL }}images/hi.jpg" />
If {{ STATIC_URL }} isn't working in your template, you're probably not using RequestContext when rendering the template.
As a brief refresher, context processors add variables into the contexts of every template. However, context processors require that you use RequestContext when rendering templates. This happens automatically if you're using a generic view, but in views written by hand you'll need to explicitly use RequestContext To see how that works, and to read more details, check out Subclassing Context: RequestContext.
Another option is the get_static_prefix template tag that is part of Django's core.
The more powerful tool is the static template tag. It builds the URL for the given relative path by using the configured STATICFILES_STORAGE storage.
{% load staticfiles %}
<img src="{% static "images/hi.jpg" %}" />
It is also able to consume standard context variables, e.g. assuming a user_stylesheet variable is passed to the template:
{% load staticfiles %}
<link rel="stylesheet" href="{% static user_stylesheet %}" type="text/css" media="screen" />
Note
There is also a template tag named static in Django's core set of built in template tags which has the same argument signature but only uses urlparse.urljoin() with the STATIC_URL setting and the given path. This has the disadvantage of not being able to easily switch the storage backend without changing the templates, so in doubt use the staticfiles static template tag.
The static files tools are mostly designed to help with getting static files successfully deployed into production. This usually means a separate, dedicated static file server, which is a lot of overhead to mess with when developing locally. Thus, the staticfiles app ships with a quick and dirty helper view that you can use to serve files locally in development.
This view is automatically enabled and will serve your static files at STATIC_URL when you use the built-in runserver management command.
To enable this view if you are using some other server for local development, you'll add a couple of lines to your URLconf. The first line goes at the top of the file, and the last line at the bottom:
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
# ... the rest of your URLconf goes here ...
urlpatterns += staticfiles_urlpatterns()
This will inspect your STATIC_URL setting and wire up the view to serve static files accordingly. Don't forget to set the STATICFILES_DIRS setting appropriately to let django.contrib.staticfiles know where to look for files additionally to files in app directories.
Warning
This will only work if DEBUG is True.
That's because this view is grossly inefficient and probably insecure. This is only intended for local development, and should never be used in production.
Additionally, when using staticfiles_urlpatterns your STATIC_URL setting can't be empty or a full URL, such as http://static.example.com/.
For a few more details on how the staticfiles can be used during development, see Static file development view.
There may be files other than your project's static assets that, for convenience, you'd like to have Django serve for you in local development. The serve() view can be used to serve any directory you give it. (Again, this view is not hardened for production use, and should be used only as a development aid; you should serve these files in production using a real front-end webserver).
The most likely example is user-uploaded content in MEDIA_ROOT. staticfiles is intended for static assets and has no built-in handling for user-uploaded files, but you can have Django serve your MEDIA_ROOT by appending something like this to your URLconf:
from django.conf import settings
# ... the rest of your URLconf goes here ...
if settings.DEBUG:
urlpatterns += patterns('',
url(r'^media/(?P<path>.*)$', 'django.views.static.serve', {
'document_root': settings.MEDIA_ROOT,
}),
)
Note, the snippet assumes your MEDIA_URL has a value of '/media/'. This will call the serve() view, passing in the path from the URLconf and the (required) document_root parameter.
Since it can become a bit cumbersome to define this URL pattern, Django ships with a small URL helper function static() that takes as parameters the prefix such as MEDIA_URL and a dotted path to a view, such as 'django.views.static.serve'. Any other function parameter will be transparently passed to the view.
An example for serving MEDIA_URL ('/media/') during development:
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = patterns('',
# ... the rest of your URLconf goes here ...
) + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
Note
This helper function will only be operational in debug mode and if the given prefix is local (e.g. /static/) and not a URL (e.g. http://static.example.com/).
The basic outline of putting static files into production is simple: run the collectstatic command when static files change, then arrange for the collected static files directory (STATIC_ROOT) to be moved to the static file server and served.
Of course, as with all deployment tasks, the devil's in the details. Every production setup will be a bit different, so you'll need to adapt the basic outline to fit your needs. Below are a few common patterns that might help.
If you want to serve your static files from the same server that's already serving your site, the basic outline gets modified to look something like:
You'll probably want to automate this process, especially if you've got multiple web servers. There's any number of ways to do this automation, but one option that many Django developers enjoy is Fabric.
Below, and in the following sections, we'll show off a few example fabfiles (i.e. Fabric scripts) that automate these file deployment options. The syntax of a fabfile is fairly straightforward but won't be covered here; consult Fabric's documentation, for a complete explanation of the syntax..
So, a fabfile to deploy static files to a couple of web servers might look something like:
from fabric.api import *
# Hosts to deploy onto
env.hosts = ['www1.example.com', 'www2.example.com']
# Where your project code lives on the server
env.project_root = '/home/www/myproject'
def deploy_static():
with cd(env.project_root):
run('./manage.py collectstatic -v0 --noinput')
Most larger Django apps use a separate Web server -- i.e., one that's not also running Django -- for serving static files. This server often runs a different type of web server -- faster but less full-featured. Some good choices are:
Configuring these servers is out of scope of this document; check each server's respective documentation for instructions.
Since your static file server won't be running Django, you'll need to modify the deployment strategy to look something like:
Here's how this might look in a fabfile:
from fabric.api import *
from fabric.contrib import project
# Where the static files get collected locally
env.local_static_root = '/tmp/static'
# Where the static files should go remotely
env.remote_static_root = '/home/www/static.example.com'
@roles('static')
def deploy_static():
local('./manage.py collectstatic')
project.rysnc_project(
remote_dir = env.remote_static_root,
local_dir = env.local_static_root,
delete = True
)
Another common tactic is to serve static files from a cloud storage provider like Amazon's S3 and/or a CDN (content delivery network). This lets you ignore the problems of serving static files, and can often make for faster-loading webpages (especially when using a CDN).
When using these services, the basic workflow would look a bit like the above, except that instead of using rsync to transfer your static files to the server you'd need to transfer the static files to the storage provider or CDN.
There's any number of ways you might do this, but if the provider has an API a custom file storage backend will make the process incredibly simple. If you've written or are using a 3rd party custom storage backend, you can tell collectstatic to use it by setting STATICFILES_STORAGE to the storage engine.
For example, if you've written an S3 storage backend in myproject.storage.S3Storage you could use it with:
STATICFILES_STORAGE = 'myproject.storage.S3Storage'
Once that's done, all you have to do is run collectstatic and your static files would be pushed through your storage package up to S3. If you later needed to switch to a different storage provider, it could be as simple as changing your STATICFILES_STORAGE setting.
For details on how you'd write one of these backends, Writing a custom storage system.
See also
The django-storages project is a 3rd party app that provides many storage backends for many common file storage APIs (including S3).
django.contrib.staticfiles began its life as django-staticfiles. If you're upgrading from django-staticfiles older than 1.0 (e.g. 0.3.4) to django.contrib.staticfiles, you'll need to make a few changes:
This document has covered the basics and some common usage patterns. For complete details on all the settings, commands, template tags, and other pieces include in django.contrib.staticfiles, see the staticfiles reference.
May 10, 2012