Serving Static Files In Django
What Are Static Files?
Static files are files that don’t change when your application is running.
These files do a lot to improve your application, but they aren’t dynamically generated by your Python web server. In a typical web application, your most common static files will be the following types:
- Cascading Style Sheets, CSS
- JavaScript
- Images
Keep in mind that even though Django will serve these files statically, there may be a complex process in place to produce the files. For instance, modern JavaScript apps often have complex processes using JavaScript build tools like webpack to build the final JavaScript files that are served to users.
Static files are crucial to your Django project because the modern web requires more than dynamically generated HTML markup. Do you visit any website that has zero styling of its HTML? These kinds of sites exist and can be awesome for making a quick tool, but most users expect websites to be aesthetically pleasing. For us, that means that we should be prepared to include some CSS styling at a minimum.
Let’s look at some configuration to see where static files live in your project, then begin to work with some examples.
Configuration
To use static files in your project, you need the django.contrib.staticfiles
app in your project’s INSTALLED_APPS
list. This is another one of the default Django applications that Django will include if you start from the startproject
command.
The staticfiles
app has a handful of settings that we need to consider to start.
I’m going to make the same recommendation about static files as I did with templates. I recommend that you create a static
directory at the root of your project to hold your static files. Similarly to templates, the staticfiles
app will look for static
directories within each of your Django apps to find files, but I find it easier to work with and locate static files if they are all in the same directory.
To make that setup work, use the STATICFILES_DIRS
setting. This setting tells Django any additional locations for static files beyond looking for a static
directory within each app.
Next, we can define the URL path prefix that Django will use when it serves a static file. Let’s says you have site.css
in the root of your project’s static
directory. You probably wouldn’t want the file to be accessible as mysite.com/site.css
. To do so would mean that static files could conflict with URL paths that your app might need to direct to a view.
With STATIC_URL
set, we can access site.css
from mysite.com/static/site.css
.
There’s one more crucial setting that we need to set, and it is called STATIC_ROOT
. When we deploy our Django project, Django wants to find all static files from a single directory. The reason for this is for efficiency. It’s possible for Django to search through all the app static
directories and any directories set in STATICFILES_DIRS
whenever it searches for a file to serve, but that would be slow.
Instead, Django will put all static files into a single directory so that searching for a file is a search through a single file tree. We’ll look more at how this happens in the deployment section later in this article.
Once we set STATIC_ROOT
, Django will have the desired output location for static files. If you set the path somewhere in your repository, don’t forget to put that path in your .gitignore
if you’re using version control with Git (and I highly recommend that you do!). I happen to set my STATIC_ROOT
to a staticfiles
directory.
Now that we know how to configure static files, we’re ready to see how to use them in our Django code.
Working With Static Files
The primary way of working with static files is with a template tag. The static
template tag will help render the proper URL for a static file for your site.
Here’s an example template to consider:
In this example, I’m assuming that there is a css
directory in my static
directory with a site.css
file inside. Django will render this template tag as /static/css/site.css
in the most basic format. We should also note that I had to include {% load static %}
to ensure that the static
template tag was available.
In practice, I find that this load
requirement bites me all the time. Thankfully, the TemplateSyntaxError
that Django will raise provides a good clue on how to fix this issue. The exception says “Did you forget to register or load this tag?” How helpful of the Django developers to tell us what we’re probably missing!
Since we know that STATIC_URL
is /static/
from the configuration section, why don’t I hardcode the link tag path to /static/css/site.css
? You could, and that might work, but you’ll probably run into some long term problems.
- What if you ever wanted to change
STATIC_URL
? Maybe you want to change it to something shorter like/s/
. If you hardcode the name, now you have more than one place to change. - Using some extra features, Django may change the name of a file to something unique by adding a hash to the file name. With a hardcoded path of
/static/css/site.css
, this may lead to a 404 response if Django expects the unique name instead. We’ll see what the unique name is for in the next section.
We should remember to use the static
tag in the same way that we use the url
tag when we want to resolve a Django URL path. Both of these tags help avoid hardcoding paths that can change.
Less commonly, we can refer to a static file from Python code. You can do this by calling a static
function defined in the same location as the static
template tag function, but the function is not located where you might expect it. Instead of importing from the staticfiles
app, Django defines these functions in django.templatetags.static
.
For example, if you wanted to serve a JSON view that feeds a JavaScript client application the path to a CSS file, you might write:
Deployment Considerations
In the configuration section, we saw the STATIC_ROOT
option. That option will collect all the static files into a single directory, but when does it do that? And how do static files work when we run in development mode and don’t have all the files in the STATIC_ROOT
location?
When you deploy your application to a server, one crucial setting to disable is the DEBUG
setting. If DEBUG
is on, all kinds of secret data can leak from your application, so the Django developers expect DEBUG
to be False
for your live site. Because of this expectation, certain parts of Django behave differently when DEBUG
changes, and the staticfiles
app is one such part.
When DEBUG
is True
and you are using the runserver
command to run the development web server, Django will search for files using a set of “finders” whenever a user requests a static file. These finders are defined by the STATICFILES_FINDERS
setting, which defaults to:
As you might guess, the FileSystemFinder
looks for any static files found in the file system directory that we listed in STATICFILES_DIRS
. The AppDirectoriesFinder
looks for static files in the static
directory of each Django application that you have. You can see how this gets slow when you realize that Django will walk through len(STATICFILES_DIRS) + len(INSTALLED_APPS)
before giving up to find a single file.
To make this whole process faster, we turn DEBUG
to False
. When DEBUG
is False
, all of the slow machinery that searches for files throughout your project for static file requests is turned off. Django only looks in the STATIC_ROOT
directory for files.
Since the finders are off when DEBUG
is True
, we have to make sure that STATIC_ROOT
is filled with all the proper files. To put all the static files into place, you can use the collectstatic
command.
collectstatic
will copy all the files it discovers from iterating through each finder and collecting files from what a finder lists. In my example below, my Django project directory is myproject
, and I set STATIC_ROOT
to staticfiles
.
When deploying your application to your server, you would run collectstatic
before starting the web server. By doing that, you ensure that the web server can access any static files that the Django app might request.
For more information check this article .
I will post the deployment process of static files in cloud storages in later tutorials.
Happy reading..