loading...
Learn Django

Django Static Files Tutorial

wsvincent profile image William S. Vincent Originally published at learndjango.com ・4 min read

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/'

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

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:

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

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

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.

Posted on by:

wsvincent profile

William S. Vincent

@wsvincent

I teach Django at LearnDjango.com. Django Software Foundation Board Member. Author of three books, co-host of Django Chat podcast, and co-author of Django News newsletter.

Learn Django

Free tutorials, courses, and books on Django.

Discussion

markdown guide