Основные моменты Django: работа со статическими активами и медиафайлами (часть 4)
Опубликовано: 2022-03-10Веб-сайты Django содержат множество файлов. Это не только исходный код конфигурации, моделей, представлений и шаблонов, но и статические ресурсы: CSS и JavaScript, изображения, значки. Как будто этого уже недостаточно, иногда пользователи приходят и хотят загрузить свои файлы на ваш сайт. Этого достаточно, чтобы вызвать недоверие у любого разработчика. Файлы везде!
Вот где я хотел бы сказать (без оговорок): «Не волнуйтесь, Джанго прикроет вашу спину!» Но, к сожалению, при работе со статическими активами и медиафайлами необходимо учитывать множество предостережений.
Сегодня мы рассмотрим хранение и обслуживание файлов как для односерверных, так и для масштабируемых развертываний с учетом таких факторов, как сжатие, кэширование и доступность. Мы также обсудим затраты и преимущества CDN и выделенных решений для хранения файлов.
Примечание . Это не руководство по развертыванию сайта Django на какой-либо конкретной платформе. Вместо этого, как и другие статьи из серии Django Highlights (см. ниже), она предназначена для использования в качестве руководства для разработчиков и дизайнеров интерфейсов, чтобы понять другие части процесса создания веб-приложения. Сегодня мы сосредоточимся на том, что происходит после того, как исправление стиля или красивая графика, которую вы только что закончили, отправляются в мастер. Вместе мы разработаем интуитивное представление о стратегиях, доступных разработчикам Django для предоставления этих файлов пользователям по всему миру безопасным, производительным и экономичным способом.
Предыдущие части серии:
- Часть 1: Пользовательские модели и аутентификация
- Часть 2: Создание шаблонов строк сохранения
- Часть 3: Модели, администрирование и использование реляционной базы данных
Определения
Большинство из этих терминов довольно просты, но стоит потратить время на то, чтобы установить общий словарь для этого обсуждения.
Три типа файлов в реальном приложении Django:
- Исходный код
Файлы Python и HTML, созданные с помощью платформы Django. Эти файлы являются ядром приложения. Файлы исходного кода, как правило, довольно маленькие, измеряются в килобайтах. - Статические файлы
Эти файлы, также называемые «статическими активами», включают CSS и JavaScript, написанные разработчиком приложения и сторонними библиотеками, а также PDF-файлы, установщики программного обеспечения, изображения, музыку, видео и значки. Эти файлы используются только на стороне клиента. Размер статических файлов варьируется от нескольких килобайт CSS до гигабайт видео. - Медиафайлы
Любой файл, загруженный пользователем, от изображений профиля до личных документов, называется медиафайлом. Эти файлы необходимо безопасно и надежно хранить и извлекать для пользователя. Медиафайлы могут быть любого размера, пользователь может загрузить пару килобайт открытого текста на несколько гигабайт видео. Если вы находитесь на последнем конце этой шкалы, вам, вероятно, нужен более специализированный совет, чем эта статья готова дать.
Два типа развертывания Django:
- Один сервер
Развертывание Django на одном сервере — это именно то, на что это похоже: все находится на одном сервере. Эта стратегия очень проста и очень похожа на среду разработки, но не может эффективно обрабатывать большие или непостоянные объемы трафика. Подход с одним сервером применим только для учебных или демонстрационных проектов, а не для реальных приложений, требующих надежного времени безотказной работы. - Масштабируемость
Существует множество различных способов развертывания проекта Django, которые позволяют масштабировать его в соответствии с потребностями пользователей. Эти стратегии часто включают запуск и отключение множества серверов и использование таких инструментов, как балансировщики нагрузки и управляемые базы данных. К счастью, для целей этой статьи мы можем эффективно объединить в эту категорию все, что сложнее, чем развертывание с одним сервером.
Вариант 1: Джанго по умолчанию
Небольшие проекты выигрывают от простой архитектуры. Стандартная обработка статических ресурсов и медиафайлов в Django очень проста. Для каждого у вас есть корневая папка, в которой хранятся файлы и которая находится рядом с исходным кодом на сервере. Простой. Эти корневые папки создаются и управляются в основном с помощью конфигурации yourproject/settings.py .
Статические активы
Самое важное, что нужно понимать при работе со статическими файлами в Django, — это команда python manage.py collectstatic
. Эта команда просматривает статическую папку каждого приложения в проекте Django и копирует все статические ресурсы в корневую папку. Выполнение этой команды является важной частью развертывания проекта Django. Рассмотрим следующую структуру каталогов:
- project - project - settings.py - urls.py - ... - app1 - static/ - app1 - style.css - script.js - img.jpg - templates/ - views.py - ... - app2 - static/ - app2 - style.css - image.png - templates/ - views.py - ...
Также предположим, что в файле project/settings.py указаны следующие параметры:
STATIC_URL = "/static/" STATIC_ROOT = "/path/on/server/to/djangoproject/static"
Запуск команды python manage.py collectstatic
создаст на сервере следующую папку:
- /path/on/server/to/djangoproject/static - app1 - style.css - script.js - img.jpg - app2 - style.css - image.png
Обратите внимание, что в каждой статической папке есть еще одна папка с именем приложения. Это необходимо для предотвращения конфликтов пространств имен после сбора статических файлов; как вы можете видеть в приведенной выше файловой структуре, это разделяет app1/style.css и app2/style.css . Отсюда приложение будет искать статические файлы в этой структуре в STATIC_ROOT
во время производства. Таким образом, ссылайтесь на статические файлы в шаблоне в app1/templates/ следующим образом:
{% load static %} <link rel="stylesheet" type="text/css" href="{% static "app1/style.css" %}">
Django автоматически определяет, откуда взять статический файл в процессе разработки, чтобы смоделировать такое поведение, вам не нужно запускать collectstatic
во время разработки.
Дополнительные сведения см. в документации Django.
Медиафайлы
Представьте себе профессиональный сетевой сайт с базой данных пользователей. У каждого из этих пользователей будет связанный профиль, который может содержать, среди прочего, изображение аватара и резюме. Вот краткий пример модели этой информации:
from django.db import models from django.contrib.auth.models import User def avatar_path(instance, filename): return "avatar_{}_{}".format(instance.user.id, filename) class Profile(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE) resume = models.FileField(upload_to="path/string") avatar = models.ImageField(upload_to=avatar_path)
Чтобы это работало, вам нужны следующие параметры в project/settings.py , как и со статическими активами:
MEDIA_URL = "/media/" MEDIA_ROOT = "/path/on/server/to/media"
ImageField
наследуется от FileField
, поэтому имеет те же параметры и возможности. Оба поля имеют необязательный аргумент upload_to
, который принимает строку, представляющую собой путь, и добавляет ее к MEDIA_ROOT
для сохранения файла, который затем доступен по тому же пути поверх MEDIA_URL
. Аргумент upload_to
также может принимать функцию, возвращающую строку, как показано на примере функции avatar_path
.
Обязательно исключите каталог медиафайлов и его содержимое из системы контроля версий. Его содержимое может конфликтовать, когда два разработчика тестируют одно и то же приложение на разных машинах, и, в отличие от статических ресурсов, оно не является частью развертываемого приложения Django.
Вариант 2: Django с сервисами
Моя основная философия — использовать инструменты для того, в чем они лучше всего. Django — это потрясающая среда, которая предоставляет отличные готовые инструменты для аутентификации пользователей, рендеринга на стороне сервера, работы с моделями и формами, административными функциями и десятками других важных аспектов создания веб-приложений. Однако его инструментарий для обработки статических ресурсов и медиафайлов, на мой взгляд, не очень подходит для работы на масштабируемых сайтах. Разработчики ядра Django признают, что многие люди выбирают альтернативные подходы к работе с этими файлами в рабочей среде; фреймворк очень хорошо убирает вас с дороги, когда вы это делаете. Большинство сайтов Django, предназначенных для общего использования, захотят включать статические ресурсы и обрабатывать медиафайлы, используя эти подходы, не относящиеся к Django.
Статические активы в CDN
В то время как небольшие и средние проекты могут обойтись без него, CDN (сеть доставки контента) проста в использовании и повышает производительность приложений любого размера. CDN — это сеть серверов, как правило, по всему миру, которая распространяет и обслуживает веб-контент, в основном статические ресурсы. Популярные CDN включают Cloudflare CDN, Amazon CloudFront и Fastly. Чтобы использовать CDN, вы загружаете свои статические файлы, а затем ссылаетесь на них в своем приложении следующим образом:

<link rel="stylesheet" type="text/css" href="https://cdn.example.com/path/to/your/files/app1/style.css">
Этот процесс легко интегрируется с вашими сценариями развертывания Django. После запуска команды python manage.py collectstatic
скопируйте сгенерированный каталог в CDN (этот процесс существенно зависит от используемой вами службы), а затем удалите статические ресурсы из пакета развертывания Django.
В процессе разработки вам понадобится доступ к другим копиям ваших статических ресурсов, чем в рабочей среде. Таким образом, вы можете вносить изменения локально, не затрагивая рабочую площадку. Вы можете либо использовать локальные ресурсы, либо запустить второй экземпляр CDN для доставки файлов. Настройте yourproject/settings.py с какой-либо пользовательской переменной, например CDN_URL
, и используйте это значение в своих шаблонах, чтобы убедиться, что вы используете правильную версию ресурсов в разработке и производстве.
И последнее замечание: многие библиотеки для CSS и JavaScript имеют бесплатные CDN, которые могут использовать большинство веб-сайтов. Если вы загружаете, скажем, Bootstrap 4 или underscore.js, вы можете избежать хлопот, связанных с использованием собственной копии в разработке, и затрат на обслуживание собственных копий в производстве с помощью этих общедоступных CDN.
Медиафайлы с выделенным хранилищем файлов
Ни один рабочий сайт Django не должен хранить пользовательские файлы в простой папке /media/ где-то на сервере, на котором запущен сайт. Вот три из многих причин, почему бы и нет:
- Если вам нужно масштабировать сайт, добавив несколько серверов, вам нужен какой-то способ копирования и синхронизации загруженных файлов между этими серверами.
- В случае сбоя сервера исходный код резервируется в вашей системе контроля версий, но медиафайлы не копируются по умолчанию, если только вы не настроили свой сервер для этого, но для этого вам лучше использовать выделенный файловый магазин.
- В случае злонамеренной активности несколько лучше хранить загружаемые пользователем файлы на сервере, отдельном от того, на котором запущено приложение, хотя это никоим образом не отменяет требования проверки загружаемых пользователем файлов.
Интеграция третьей стороны для хранения загруженных вами файлов очень проста. Вам не нужно ничего менять в своем коде, за исключением, возможно, удаления или изменения значения upload_to
FileField
в ваших моделях и настройки нескольких параметров. Например, если вы планируете хранить свои файлы в AWS S3, вам нужно сделать следующее, что очень похоже на процесс хранения файлов в Google Cloud, Azure, Backblaze или аналогичных конкурирующих сервисах.
Во-первых, вам нужно установить библиотеки boto3
и django-storages
storages. Затем вам нужно настроить корзину и роль IAM на AWS, что выходит за рамки этой статьи, но вы можете посмотреть инструкции здесь. После того, как все это настроено, вам нужно добавить три переменные в ваш проект/settings.py :
DEFAULT_FILE_STORAGE = "storages.backends.s3boto3.S3Boto3Storage" AWS_STORAGE_BUCKET_NAME = "BUCKET_NAME" AWS_S3_REGION_NAME = "us-east-2"
Кроме того, вам потребуется настроить доступ к вашей корзине AWS с учетными данными. В некоторых руководствах показано добавление идентификатора и секретного ключа в файл настроек или в качестве переменных среды, но это небезопасная практика. Вместо этого используйте django-storages
с интерфейсом командной строки AWS для настройки ключей, как описано здесь. Вас также может заинтересовать документация по django-storages
.
Вы не хотите, чтобы медиафайлы разработки или тестирования смешивались с загрузками от реальных пользователей. Избежать этого довольно просто: настройте несколько сегментов: один для разработки (или по одному для каждого разработчика), один для тестирования и один для производства. Затем все, что вам нужно изменить, — это параметр AWS_STORAGE_BUCKET_NAME
для каждой среды, и все готово.
Производительность и доступность
Существует множество факторов, влияющих на производительность и надежность вашего сайта. Вот некоторые важные из них при рассмотрении статических и мультимедийных файлов, которые имеют значение независимо от того, какой подход вы используете для управления ими.
Расходы
Обслуживание файлов пользователю стоит денег по двум причинам: хранение и пропускная способность. Вы должны платить хостинг-провайдеру за хранение файлов для вас, но вы также должны платить им за обслуживание файлов. Пропускная способность значительно дороже, чем хранение (например, AWS S3 взимает 2,3 цента за гигабайт за хранение по сравнению с 9 центами за гигабайт за передачу данных в Интернет на момент написания). Экономика хранилища файлов, такого как S3 или CDN, отличается от экономики универсального хоста, такого как дроплет Digital Ocean. Воспользуйтесь специализацией и эффектом масштаба, переместив дорогостоящие файлы в службы, предназначенные для них. Кроме того, многие файловые хранилища и CDN предлагают бесплатные планы, поэтому сайты, которые могут быть достаточно маленькими, чтобы обойтись без них, могут вместо этого сделать это и воспользоваться преимуществами без каких-либо дополнительных затрат на инфраструктуру.
Сжатие и транскодирование
Большинство проблем, вызванных статическими активами, такими как фотографии и видео, связаны с тем, что они представляют собой большие файлы. Естественно, разработчики решают эту проблему, пытаясь уменьшить размер этих файлов. Есть несколько способов сделать это, используя сочетание сжатия и транскодирования в двух основных категориях: без потерь и с потерями. Сжатие без потерь сохраняет исходное качество ресурсов, но обеспечивает относительно небольшое уменьшение размера файла. Сжатие с потерями или перекодирование в формат с потерями позволяет значительно уменьшить размеры файлов за счет потери части качества исходного артефакта. Примером этого является перекодирование видео с более низким битрейтом. Для получения подробной информации ознакомьтесь с этой статьей об оптимизации доставки видео. При обслуживании больших файлов через Интернет скорость полосы пропускания часто требует, чтобы вы обслуживали сильно сжатые артефакты, требующие сжатия с потерями.
Если вы не YouTube, сжатие и перекодирование не происходит на лету. Статические ресурсы должны быть соответствующим образом отформатированы перед развертыванием, и вы можете установить базовые ограничения по типу и размеру файлов для загрузки пользователями, чтобы обеспечить достаточное сжатие и соответствующее форматирование медиафайлов ваших пользователей.
Минификация
Хотя файлы JavaScript и CSS обычно не так велики, как изображения, их часто можно сжать, чтобы втиснуть в меньшее количество байтов. Этот процесс называется минификацией. Минимизация не меняет кодировку файлов, они по-прежнему являются текстовыми, и минимизированный файл по-прежнему должен быть допустимым кодом для исходного языка. Минифицированные файлы сохраняют свои исходные расширения.
Главное, что удаляется в минифицированном файле, — это ненужные пробелы, а с точки зрения компьютера почти все пробелы в CSS и JavaScript не нужны. Схемы минификации также сокращают имена переменных и удаляют комментарии.
Минификация по умолчанию запутывает код; как разработчик, вы должны работать исключительно с неминифицированными файлами. Некоторый автоматический шаг в процессе развертывания должен минимизировать файлы перед их сохранением и обслуживанием. Если вы используете библиотеку, предоставленную сторонним CDN, убедитесь, что вы используете уменьшенную версию этой библиотеки, если она доступна. Файлы HTML можно минимизировать, но поскольку Django использует рендеринг на стороне сервера, стоимость обработки на лету, скорее всего, перевесит небольшое уменьшение размера страницы.
Глобальная доступность
Точно так же, как отправка письма соседу занимает меньше времени, чем его отправка по стране, так и передача данных поблизости занимает меньше времени, чем по всему миру. Одним из способов повышения производительности страницы с помощью CDN является копирование ресурсов на серверы по всему миру. Затем, когда клиент делает запрос, он получает статические ресурсы с ближайшего сервера (часто называемого граничным узлом), что сокращает время загрузки. Одним из преимуществ использования CDN с сайтом Django является отделение глобального распространения ваших статических ресурсов от глобального распространения вашего кода.
Кэширование на стороне клиента
Что может быть лучше, чем статический файл на сервере рядом с вашим пользователем? Наличие статического файла, уже сохраненного на устройстве вашего пользователя! Кэширование — это процесс сохранения результатов вычислений или запросов для более быстрого повторного доступа к ним. Точно так же, как таблица стилей CSS может кэшироваться по всему миру в CDN, она может кэшироваться в браузере клиента при первой загрузке страницы с вашего сайта. Затем таблица стилей доступна на самом устройстве при последующих запросах, поэтому клиент делает меньше запросов, сокращается время загрузки страницы и снижается использование пропускной способности.
Браузеры выполняют свои собственные операции кэширования, но если ваш сайт имеет значительный трафик, вы можете оптимизировать поведение кэширования на стороне клиента, используя структуру кэширования Django.
В заключение
Опять же, моя основная философия заключается в том, чтобы использовать инструменты для того, в чем они лучше всего разбираются. Проекты с одним сервером и небольшие масштабируемые развертывания с небольшими статическими активами могут использовать встроенное управление статическими активами Django, но большинство приложений должны отделять активы для обслуживания через CDN.
Если ваш проект предназначен для любого реального использования, не храните медиафайлы с помощью метода Django по умолчанию, вместо этого используйте службу. При достаточном трафике, где «достаточный трафик» — это относительно небольшое число в масштабах Интернета, дополнительные сложности с архитектурой, процессом разработки и развертыванием более чем окупаются производительностью, надежностью и экономией средств при использовании отдельный CDN и решение для хранения файлов для статических и мультимедийных файлов соответственно.
Рекомендуемое чтение
- Часть 1: Пользовательские модели и аутентификация
- Часть 2: Создание шаблонов строк сохранения
- Часть 3: Модели, администрирование и использование реляционной базы данных