DEV Community

Will Vincent for Learn Django

Posted on • Originally published at learndjango.com

Django Static Files Tutorial

Static files are a common source of confusion for Django newcomers. The term "static files" refers to files like CSS, JavaScript, or images that do not change in a web app. They remain static. For local development, static files are served up by the local Django web server and minimal configuration is required. Django does not support serving static files in production, however, so a number of additional configurations are required to get them working.

In this tutorial, we'll look at how static files work in Django, how to configure them locally, as well as using WhiteNoise to serve them in production.

Local Development

When you first run startproject to create a new Django project, a settings.py file is automatically created which defaults to local development settings. These include DEBUG set to True and DATABASES set to SQLite. It also includes, near the bottom of the file, a solitary line for static files:

# settings.py
STATIC_URL = '/static/'
Enter fullscreen mode Exit fullscreen mode

The STATIC_URL setting controls the actual URL used to locate static files. In this case, that would be /static/, so in local development, 127.0.0.1:8000/static/ or localhost:8000/static/. In production, if our website was called example.com, the static files would be located at example.com/static/.

There are two steps required to use static files locally:

  • create a static directory
  • add {% load static %} at the top of a template and use the static template tag

The static directory should be in the same folder as manage.py. Add any desired static files here. For example, you might create another folder called css and within it a file called base.css. To include this file in a template, make sure the first line of the file is {% load static %} and the link would look something like this: <link href="{% static 'css/base.css' %}" rel="stylesheet">. The static template tag is used variable, could also hardcode the result here. This is useful later on for production.

That's it!

collectstatic

For production, Django looks through the entire project for static files (STATICFILES_DIRS) and collects all available static files via the collectstatic command into a dedicated directory (STATIC_ROOT). The way in which the files are stored is dictated by STATICFILES_STORAGE. We therefore need to add these three additional configurations and run the collectstatic command in production every time there is a change to the static files.

STATICFILES_DIRS tells Django where to look for static files in a Django project. Often, this is simply the static directory but there could be static directories in various apps or other locations. When the collectstatic command is run, Django refers to the list of directories here when creating a dedicated directory for production serving.

STATIC_ROOT is the location of the collected static files, often named staticfiles.

STATICFILES_STORAGE is the file storage engine used when collecting static files with the collecstatic command. By default, it is implicitly set to django.contrib.staticfiles.storage.StaticFilesStorage.

In your local Django project, add these three settings to your settings.py file.

# settings.py
STATIC_URL = '/static/'
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static'),] # new
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') # new
STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.StaticFilesStorage' # new
Enter fullscreen mode Exit fullscreen mode

Then run the command python manage.py collectstatic.

(env) $ python manage.py collectstatic
You have requested to collect static files at the destination
location as specified in your settings.

This will overwrite existing files!
Are you sure you want to do this?

Type 'yes' to continue, or 'no' to cancel:
Enter fullscreen mode Exit fullscreen mode

Type yes to continue and hit the Enter key. A new staticfiles directory will be created which has folders for admin (the built-in admin has its own static files), staticfiles.json, and whatever directories are in your static folder.

If you now add a new static file to static, it will be available for local usage. It is only for production where the file won't be present, unless you run python manage.py collectstatic each and every time. For this reason, running collectstatic is typically added to deployment pipelines and is done by default on Heroku.

WhiteNoise

Even though we've configured our Django project to collect static files properly, there's one more step involved which is not included in the official Django docs. That is the configuration of WhiteNoise, radically simplified static file serving for Python web apps. Is it possible to use another package to serve Python static files? Yes. Have I ever seen it done over the last 5 years? No. Everyone uses WhiteNoise and you should, too, since Django won't serve static files in production on its own.

(env) $ pipenv install whitenoise==5.1.0
Enter fullscreen mode Exit fullscreen mode

Then in the settings.py file, add whitenoise to the INSTALLED_APPS above the built-in staticfiles app. Under MIDDLEWARE, add a new WhiteNoiseMiddleware on the third line. And at the bottom of the file, change STATICFILES_STORAGE to use WhiteNoise. It should look like the following:

# settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'whitenoise.runserver_nostatic', # new
    'django.contrib.staticfiles',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'whitenoise.middleware.WhiteNoiseMiddleware', # new
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

...

STATIC_URL = '/static/'
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static'),]
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage' # new
Enter fullscreen mode Exit fullscreen mode

That's it! Run python manage.py collectstatic again so that the files are stored using WhiteNoise. And then deploy with confidence to the hosting platform of your choice.

Top comments (2)

Collapse
 
shahidullah profile image
shahid-ullah

Good Explanation. You are helping me a lot.

Collapse
 
codebyline profile image
Yumei Leventhal

Just the information I've been looking for! Thanks! How does /media/ figure into collectstatic? I am not even sure I am asking the right question, except the two confuse me to no end.