Работа со статическими и медиа-файлами в Django

В этой статье рассматривается, как работать со статическими и мультимедийными файлами в проекте Django, локально и в рабочей среде.

Цели

К концу этой статьи вы сможете:

  1. Описать три различных типа файлов, которые вы обычно встречаете в проектах Django
  2. Объяснить разницу между статическими файлами и медиафайлами мультимедиа
  3. Работать как со статическими, так и с мультимедийными файлами локально и в рабочей среде

Типы файлов

Django - это фреймворк для веб-приложений с полным стеком. Он поставляется с большим количеством батареек, которые вы можете использовать для создания полнофункционального веб-приложения, включая управление статическими файлами и медиафайлами мультимедиа.

Прежде чем мы рассмотрим как, давайте начнем с некоторых определений.

Что такое статические и медиафайлы?

Во-первых, в проекте Django обычно можно найти следующие три типа файлов:

  1. Исходный код: Это ваши основные модули Python и HTML-файлы, которые составляют каждый проект Django, где вы определяете свои модели, представления и шаблоны.
  2. Статические файлы: Это ваши таблицы стилей CSS, файлы JavaScript, шрифты и изображения. Поскольку обработка данных не требуется, эти файлы очень экономичны с точки зрения энергопотребления, поскольку их можно просто использовать как есть. Кроме того, их гораздо проще кэшировать.
  3. Медиафайл: Это файлы, которые загружает пользователь.

В этой статье речь пойдет о статических файлах и файлах мультимедиа. Хотя названия у них разные, оба представляют собой обычные файлы. Существенная разница заключается в том, что статические файлы хранятся в системе управления версиями и поставляются вместе с файлами исходного кода во время развертывания. С другой стороны, медиафайлы - это файлы, которые загружают ваши конечные пользователи (внутренние и внешние) или которые динамически создаются вашим приложением (часто как побочный эффект каких-либо действий пользователя).

Почему вы должны по-разному относиться к статическим файлам и медиафайлам мультимедиа?

  1. Вы не можете доверять файлам, загруженным конечными пользователями, поэтому к медиафайлам нужно относиться по-другому.
  2. Возможно, вам потребуется выполнить обработку загруженных пользователем медиафайлов, чтобы улучшить их качество - например, вы могли бы оптимизировать загруженные изображения для поддержки различных устройств.
  3. Вы же не хотите, чтобы загруженный пользователем файл случайно заменил статический файл.

Дополнительные примечания:

  1. Статические и мультимедийные файлы иногда называют статическими и мультимедийными ресурсами.
  2. Администратор Django поставляется с некоторыми статическими файлами, которые хранятся в системе управления версиями на GitHub.
  3. Путаницу между статическими файлами и медиафайлами усугубляет то, что документация Django сама по себе не очень хорошо проводит различие между ними.

Статические файлы

Django предоставляет мощный инструмент для работы со статическими файлами, который удачно назван staticfiles.

Если вы новичок в приложении staticfiles, ознакомьтесь с Руководством по управлению статическими файлами (например, изображениями, JavaScript, CSS) из документации Django.

Приложение staticfiles для Django предоставляет следующие основные компоненты:

  1. Настройки
  2. Команды управления
  3. Классы хранения
  4. Теги шаблона

Настройки

Существует ряд параметров, которые вам могут потребоваться для настройки в зависимости от вашей среды:

  1. STATIC_URL: URL-адрес, по которому пользователь может получить доступ к вашим статическим файлам в браузере. Значение по умолчанию равно /static/, что означает, что ваши файлы будут доступны по адресу http://127.0.0.1:8000/static/ в режиме разработки, например, http://127.0.0.1:8000/static/css/main.css.
  2. STATIC_ROOT: Абсолютный путь к каталогу, из которого ваше приложение Django будет обслуживать ваши статические файлы. Когда вы запустите управляющую команду collectstatic (подробнее об этом чуть позже), она найдет все статические файлы и скопирует их в этот каталог.
  3. STATICFILES_DIRS: По умолчанию статические файлы хранятся на уровне приложения по адресу <APP_NAME>/static/. Команда collectstatic будет искать статические файлы в этих каталогах. Вы также можете указать Django искать статические файлы в дополнительных расположениях с помощью STATICFILES_DIRS.
  4. ХРАНИЛИЩА: Определяет способ настройки различных серверных систем хранения для управления файлами. Каждому серверу хранилища может быть присвоен псевдоним, и существует два специальных псевдонима: default для управления файлами (с использованием FileSystemStorage в качестве механизма хранения по умолчанию) и staticfiles для управления статическими файлами (с использованием StaticFilesStorage по умолчанию).
  5. STATICFILES_FINDERS: Этот параметр определяет серверные программы поиска файлов, которые будут использоваться для автоматического поиска статических файлов. По умолчанию используются параметры поиска FileSystemFinder и AppDirectoriesFinder:
    • FileSystemFinder - использует параметр STATICFILES_DIRS для поиска файлов.
    • AppDirectoriesFinder - выполняет поиск файлов в "статической" папке в каждом приложении Django в рамках проекта.

Команды управления

Приложение static files предоставляет следующие команды управления:

  1. collectstatic это команда управления, которая собирает статические файлы из различных местоположений, т.е. из <APP_NAME>/static/ и каталогов, указанных в параметре STATICFILES_DIRS, и копирует их в каталог STATIC_ROOT.
  2. findstatic это действительно полезная команда для использования при отладке, позволяющая точно определить, откуда берется конкретный файл.
  3. runserver запускает легкий сервер разработки для запуска вашего приложения Django в процессе разработки.

Примечания:

  1. Не помещайте статические файлы в каталог STATIC_ROOT. Именно в него автоматически копируются статические файлы после запуска collectstatic. Вместо этого всегда помещайте их в каталоги, связанные с параметром STATICFILES_DIRS или <APP_NAME>/static/.
  2. Не используйте сервер разработки в рабочей среде. Вместо этого используйте рабочий сервер приложений WSGI. Подробнее об этом чуть позже.

Краткий пример выполнения команды findstatic:

Допустим, у вас есть два приложения Django, app1 и app2. У каждого приложения есть папка с именем "static", а внутри каждой из этих папок находится файл с именем app.css. Соответствующие настройки из settings.py:

STATIC_ROOT = 'staticfiles'

INSTALLED_APPS = [
    ...
    'app1',
    'app2',
]

При запуске python manage.py collectstatic будет создан каталог "staticfiles", в который будут скопированы соответствующие статические файлы:

$ ls staticfiles/

admin   app.css

Существует только один файл app.css, потому что при наличии нескольких файлов с одинаковыми именами staticfiles finder будет использовать первый найденный файл. Чтобы увидеть, какой файл был скопирован, вы можете использовать команду findstatic:

$ python manage.py findstatic app.css

Found 'app.css' here:
  /app1/static/app.css
  /app2/static/app.css

Поскольку собирается только первый обнаруженный файл, чтобы проверить источник app.css, который был скопирован в каталог "staticfiles", выполните:

$ python manage.py findstatic app.css --first

Found 'app.css' here:
  /app1/static/app.css

Классы хранения

При выполнении команды collectstatic Django использует классы хранилища для определения способа хранения статических файлов и доступа к ним. Опять же, это настраивается с помощью параметра ХРАНИЛИЩА.

Класс хранилища по умолчанию - StaticFilesStorage. За кулисами StaticFilesStorage используется класс FileSystemStorage для хранения файлов в локальной файловой системе.

Возможно, вы захотите изменить настройки по умолчанию в рабочей среде. Например, django-storages предоставляет несколько пользовательских классов хранилища для разных поставщиков облачных услуг/CDN. Вы также можете написать свой собственный класс хранилища, используя file storage API. Подробнее об этом читайте в разделе Обслуживание статических файлов из облачного сервиса или CDN.

Классы хранения могут использоваться для выполнения задач постобработки, таких как минимизация.

Теги шаблона

Чтобы загрузить статические файлы в ваши файлы шаблонов, вам необходимо:

  1. Добавьте {% load static %} в начало файла шаблона
  2. Затем для каждого файла, который вы хотите связать, добавьте тег шаблона {% static %}

Например:

{% load static %}

<link rel="stylesheet" href="{% static 'base.css' %}">

Вместе эти теги генерируют полный URL-адрес, например, /static/base.css, на основе конфигурации статических файлов в settings.py файле.

Вам всегда следует загружать статические файлы таким образом, а не жестко кодировать URL напрямую, чтобы вы могли изменить конфигурацию статического файла и указать на другой STATIC_URL без необходимости вручную обновлять каждый шаблон.

Подробнее об этих тегах шаблона читайте в разделе статические из раздела Встроенные теги и фильтры шаблона.

Статические файлы в режиме разработки

Во время разработки, если для параметра DEBUG установлено значение TRUE и вы используете приложение staticfiles, вы можете обрабатывать статические файлы с помощью Сервер разработки Django. Вам даже не нужно выполнять команду collecstatic.

Типичная конфигурация для разработки:

# settings.py

STATIC_URL = '/static/'
STATIC_ROOT = BASE_DIR / 'staticfiles'
STATICFILES_DIRS = [BASE_DIR / 'static',]
STORAGES = {
    "staticfiles": {
        "BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage",
    },
}

Django static files in development mode

Статические файлы в рабочей среде

Обработка статических файлов в рабочей среде не так проста, как в вашей среде разработки, поскольку вы будете использовать либо WSGI (например, Gunicorn), либо ASGI (например, Uvicorn) совместимый сервер веб-приложений, который используется для обслуживания динамического контента, т.е. ваших файлов исходного кода Django.

Существует несколько различных способов обработки статических файлов в рабочей среде, но наиболее популярными являются два варианта:

  1. Используйте веб-сервер, такой как Nginx, чтобы направлять трафик, предназначенный для ваших статических файлов, непосредственно в статический корневой каталог (настроенный с помощью STATIC_ROOT)
  2. Используйте WhiteNoise для обработки статических файлов непосредственно с сервера веб-приложений WSGI или OSGI

Независимо от выбранного варианта, вы, вероятно, захотите использовать CDN.

Подробнее об этих параметрах читайте в Инструкции по развертыванию статических файлов.

Nginx

Пример конфигурации Nginx:

upstream hello_django {
    server web:8000;
}

server {

    listen 80;

    location / {
        proxy_pass http://hello_django;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;
        proxy_redirect off;
    }

    location /static/ {
        alias /home/app/web/staticfiles/;
    }

}

Короче говоря, когда запрос отправляется на /static/, например, на /static/base.css, Nginx попытается обработать файл из папки "/home/app/web/staticfiles/".

Интересно, как работает приведенная выше конфигурация Nginx? Ознакомьтесь с Руководством по настройке Django с помощью Postgres, Gunicorn и Nginx.

Дополнительные ресурсы:

  1. Предпочитаете хранить свои статические файлы на Amazon S3? Ознакомьтесь с Сохранением статических и мультимедийных файлов Django на Amazon S3.
  2. Предпочитаете хранить свои статические файлы в DigitalOcean Spaces? Ознакомьтесь с Хранением статических и мультимедийных файлов Django в DigitalOcean Spaces.

Белый шум

Вы можете использовать WhiteNoise для обработки статических файлов с сервера веб-приложений WSGI или OSGI.

Самая простая настройка проста. После установки пакета добавьте White Noise в список MIDDLEWARE, а затем в список всех других промежуточных программ, кроме django.middleware.security.SecurityMiddleware:

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

Затем, для поддержки сжатия и кэширования, обновите STORAGES примерно так:

STORAGES = {
    'staticfiles': {
        'BACKEND': 'whitenoise.storage.CompressedManifestStaticFilesStorage',
    }
}

Вот и все! Выключите режим отладки, выполните команду collectstatic, а затем запустите сервер веб-приложений WSGI или ASGI.

Подробнее о настройке WhiteNoise для работы с Django читайте в руководстве Использование белого шума в Django.

Медиафайлы

Опять же, медиафайлы - это файлы, которые ваши конечные пользователи (внутренние и внешние) загружают или динамически создают в вашем приложении (часто как побочный эффект некоторых действий пользователя). Обычно они не хранятся в системе управления версиями.

Почти всегда файлы, связанные с полями модели FileField или ImageField, следует рассматривать как медиафайлы.

Как и в случае со статическими файлами, обработка медиафайлов настраивается в файле settings.py.

Основные параметры конфигурации для работы с медиафайлами:

  1. MEDIA_URL: Аналогично STATIC_URL, это URL-адрес, по которому пользователи могут получить доступ к медиафайлам.
  2. MEDIA_ROOT: Абсолютный путь к каталогу, из которого ваше приложение Django будет обслуживать ваши медиафайлы.

Дополнительные параметры конфигурации приведены в разделе Загрузка файлов в разделе Настройки.

Медиафайлы в режиме разработки

Типичная конфигурация для разработки:

MEDIA_URL = '/media/'
MEDIA_ROOT = BASE_DIR / 'uploads'

К сожалению, сервер разработки Django не обслуживает медиафайлы по умолчанию. К счастью, есть очень простое решение: вы можете добавить корневой каталог мультимедиа в качестве статического пути к ROOT_URLCONF в URL-адресах вашего проекта.

Пример:

from django.conf import settings
from django.conf.urls.static import static
from django.contrib import admin
from django.urls import path, include


urlpatterns = [
    path('admin/', admin.site.urls),
    # ... the rest of your URLconf goes here ...
]

if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

Медиафайлы в процессе производства

Когда дело доходит до обработки медиафайлов в рабочей среде, у вас меньше возможностей, чем для статических файлов, поскольку вы не можете использовать WhiteNoise для обработки медиафайлов. Таким образом, вы, как правило, захотите использовать Nginx вместе с django-хранилищами для хранения медиафайлов вне локальной файловой системы, в которой ваше приложение запущено в рабочей среде.

Пример конфигурации Nginx:

upstream hello_django {
    server web:8000;
}

server {

    listen 80;

    location / {
        proxy_pass http://hello_django;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;
        proxy_redirect off;
    }

    location /media/ {
        alias /home/app/web/mediafiles/;
    }

}

Таким образом, когда запрос отправляется на /media/, например, на /media/upload.png, Nginx попытается обработать файл из папки "/home/app/web/mediafiles/".

Интересно, как работает приведенная выше конфигурация Nginx? Ознакомьтесь с Руководством по настройке Django с помощью Postgres, Gunicorn и Nginx.

Дополнительные ресурсы:

  1. Предпочитаете хранить свои медиафайлы на Amazon S3? Ознакомьтесь с Сохранением статических и мультимедийных файлов Django на Amazon S3.
  2. Предпочитаете хранить свои медиафайлы в DigitalOcean Spaces? Ознакомьтесь с Хранением статических и мультимедийных файлов Django в DigitalOcean Spaces.

Заключение

Статические файлы и медиафайлы отличаются друг от друга и должны обрабатываться по-разному в целях безопасности.

В этой статье вы увидели примеры того, как обслуживать статические и мультимедийные файлы в процессе разработки и продакшена. Кроме того, в статье также рассматривались:

  1. Различные настройки для обоих типов файлов
  2. Как Django обрабатывает их при минимальной настройке

Вы можете найти простой проект на Django с примерами обслуживания статических файлов в процессе разработки и продакшена, а также медиафайлов в процессе разработки здесь.

В этой статье рассказывается только о работе со статическими файлами и медиафайлами мультимедиа в Django. В ней не обсуждается предварительная и последующая обработка статических файлов, такая как сокращение и объединение в пакеты. Для решения таких задач вам необходимо настроить сложные процессы сборки с помощью таких инструментов, как Rollup, Parcel или webpack.

Вернуться на верх