Статические файлы: static, collectstatic, media
CSS, JavaScript, картинки, шрифты — это статика. Django помогает находить эти файлы в разработке и собирать их в одно место для продакшена.
Суть: тег {% static %} строит правильный URL к файлу. В разработке файлы отдаёт сам Django, в продакшене их собирают командой collectstatic и раздаёт веб-сервер.
Что такое статика и медиа
Файлы сайта делятся на два вида. Статика (static) — файлы, которые вы пишете как разработчик: стили, скрипты, логотипы, иконки. Они часть кода. Медиа (media) — файлы, которые загружают пользователи: аватары, вложения. Это разные понятия с разными настройками, и их часто путают.
Тег static
Никогда не пишите путь к статике вручную (/static/css/style.css). Используйте тег {% static %} — он построит правильный URL с учётом настроек и версионирования:
{% load static %}
<link rel="stylesheet" href="{% static 'blog/css/style.css' %}">
<img src="{% static 'blog/img/logo.png' %}" alt="Логотип">
<script src="{% static 'blog/js/app.js' %}"></script>
Не забудьте {% load static %} в начале шаблона — без него тег не работает.
Где лежат файлы
Как и с шаблонами, статику кладут в папку static/ внутри приложения, в подпапку с именем приложения: blog/static/blog/css/style.css. Django при APP_DIRS найдёт её автоматически. Ключевые настройки:
STATIC_URL = "static/" # префикс URL
STATICFILES_DIRS = [BASE_DIR / "static"] # общая статика проекта
STATIC_ROOT = BASE_DIR / "staticfiles" # куда соберёт collectstatic
MEDIA_URL = "media/" # для пользовательских файлов
MEDIA_ROOT = BASE_DIR / "media"
Разработка против продакшена
Это место, где новички спотыкаются. В разработке (DEBUG=True) Django сам отдаёт статику из папок приложений — удобно. В продакшене Django не должен раздавать статику: это медленно и небезопасно. Вместо этого вы запускаете collectstatic, который собирает всю статику из всех приложений в одну папку STATIC_ROOT, и эту папку раздаёт Nginx или WhiteNoise.
python manage.py collectstatic
Как это работает под капотом
collectstatic — это, по сути, обход всех источников статики и копирование файлов в одну целевую папку с дедупликацией. Эту логику легко смоделировать:
# Попробуй сам ▶ — что делает collectstatic
sources = {
"blog/static": ["blog/css/style.css", "blog/img/logo.png"],
"shop/static": ["shop/css/cart.css"],
"admin/static": ["admin/css/base.css", "admin/js/core.js"],
}
static_root = {} # одна общая папка staticfiles/
collected, skipped = 0, 0
for app, files in sources.items():
for f in files:
if f in static_root: # уже скопирован из другого источника
skipped += 1
continue
static_root[f] = app
collected += 1
print(f"Собрано файлов: {collected}, пропущено дублей: {skipped}")
print("Содержимое STATIC_ROOT:")
for path, src in sorted(static_root.items()):
print(f" {path:24} ← {src}")
Django делает то же: проходит по всем приложениям и STATICFILES_DIRS, копирует файлы в STATIC_ROOT, а ManifestStaticFilesStorage ещё и добавляет хеш к именам для сброса кеша браузера.
WhiteNoise — простой вариант для продакшена
Для небольших проектов раздавать статику можно прямо из Python через библиотеку WhiteNoise — без отдельной настройки Nginx. Она добавляется как middleware и эффективно отдаёт собранную статику с правильными заголовками кеширования.
Частые ошибки
- Хардкодить /static/ в путях. Используйте
{% static %}. - Забыть {% load static %}. Тег не сработает.
- Путать STATICFILES_DIRS и STATIC_ROOT. Первое — где искать, второе — куда собирать. Они не должны совпадать.
- Ждать, что статика заработает на проде без collectstatic. При
DEBUG=FalseDjango её не отдаёт. - Путать static и media. Пользовательские загрузки — это media с отдельными настройками.
Best practices
- Всегда обращайтесь к статике через
{% static %}. - Раскладывайте статику по подпапкам приложений во избежание конфликтов имён.
- На проде раздавайте статику через Nginx или WhiteNoise, не через Django.
- Используйте ManifestStaticFilesStorage для версионирования и сброса кеша.
Итоги
Статика — ваши CSS/JS/картинки, медиа — загрузки пользователей. Тег {% static %} строит корректные URL. В разработке файлы отдаёт Django, в продакшене — collectstatic плюс веб-сервер. Не путайте STATICFILES_DIRS и STATIC_ROOT. Дальше перейдём к формам — главному способу получать данные от пользователя.