Skip to main content

Static Files Management

Static files management in this project is handled by the django.contrib.staticfiles application. It provides a unified interface for discovering, serving, and collecting assets like CSS, JavaScript, and images across multiple applications and custom directories.

Discovery with Finders

The core of the static files system is the "finder" mechanism. Finders are responsible for locating static assets based on project settings. The two primary finders used are FileSystemFinder and AppDirectoriesFinder, both located in django/contrib/staticfiles/finders.py.

FileSystemFinder

The FileSystemFinder searches for files in the directories defined in the STATICFILES_DIRS setting. It supports optional prefixes, allowing you to map a specific directory to a sub-path in the static URL space.

# django/contrib/staticfiles/finders.py

class FileSystemFinder(BaseFinder):
def __init__(self, app_names=None, *args, **kwargs):
self.locations = []
self.storages = {}
for root in settings.STATICFILES_DIRS:
if isinstance(root, (list, tuple)):
prefix, root = root
else:
prefix = ""
if (prefix, root) not in self.locations:
self.locations.append((prefix, root))
# ... initializes storage for each location

AppDirectoriesFinder

The AppDirectoriesFinder automatically looks for a static/ subdirectory within each application listed in INSTALLED_APPS. This allows apps to ship their own assets without requiring manual configuration in STATICFILES_DIRS.

Development Serving

During development, static files are served dynamically to avoid the need for a collection step every time a file changes. This is implemented via the StaticFilesHandler in django/contrib/staticfiles/handlers.py.

The StaticFilesHandler is a WSGI middleware that intercepts requests starting with the STATIC_URL prefix. If a request matches, it uses the finders to locate the file and serves it using Django's internal file-serving views.

# django/contrib/staticfiles/handlers.py

class StaticFilesHandler(StaticFilesHandlerMixin, WSGIHandler):
def __call__(self, environ, start_response):
if not self._should_handle(get_path_info(environ)):
return self.application(environ, start_response)
return super().__call__(environ, start_response)

This handler is automatically integrated into the runserver command when DEBUG is enabled, ensuring a seamless development experience.

Production Collection

For production environments, assets must be gathered into a single location (defined by STATIC_ROOT) so they can be served efficiently by a web server like Nginx or Apache. This is performed by the collectstatic management command.

The Collection Process

The Command class in django/contrib/staticfiles/management/commands/collectstatic.py orchestrates the collection. The collect() method iterates through all registered finders, retrieves every file they find, and copies (or symlinks) them to the destination storage.

# django/contrib/staticfiles/management/commands/collectstatic.py

def collect(self):
# ... setup handler (copy_file or link_file)
found_files = {}
for finder in get_finders():
for path, storage in finder.list(self.ignore_patterns):
# Prefix the relative path if the source storage contains it
if getattr(storage, "prefix", None):
prefixed_path = os.path.join(storage.prefix, path)
else:
prefixed_path = path

if prefixed_path not in found_files:
found_files[prefixed_path] = (storage, path)
handler(path, prefixed_path, storage)
else:
# Logs a warning if a duplicate file is found
self.log("Found another file... It will be ignored", level=2)

Conflict Resolution

If multiple finders find a file with the same relative path, collectstatic only collects the first one encountered. The order of finders in STATICFILES_FINDERS and the order of apps in INSTALLED_APPS determines which file takes precedence.

Storage and Optimization

The StaticFilesStorage class in django/contrib/staticfiles/storage.py serves as the default storage backend for collected files. It is a specialized version of FileSystemStorage that defaults its location to STATIC_ROOT.

Cache Busting with Manifests

To support long-term caching, the project includes ManifestStaticFilesStorage. This storage backend performs "post-processing" during the collectstatic run:

  1. It appends a content-based hash to filenames (e.g., styles.css becomes styles.55e7c10.css).
  2. It generates a staticfiles.json manifest file that maps original paths to their hashed versions.
  3. It updates references within CSS files to point to the new hashed filenames of other assets.

Configuration and System Checks

The StaticFilesConfig class (the AppConfig for staticfiles) ensures the system is configured correctly by registering system checks during startup.

# django/contrib/staticfiles/apps.py

class StaticFilesConfig(AppConfig):
name = "django.contrib.staticfiles"
ignore_patterns = ["CVS", ".*", "*~"]

def ready(self):
checks.register(check_finders, checks.Tags.staticfiles)
checks.register(check_storages, checks.Tags.staticfiles)

These checks catch common configuration errors, such as:

  • staticfiles.E001: STATICFILES_DIRS is not a list or tuple.
  • staticfiles.E002: STATIC_ROOT is accidentally included within STATICFILES_DIRS.
  • staticfiles.E003: A prefix in STATICFILES_DIRS ends with a slash.