Как написать пользовательский класс хранилища
Если вам нужно предоставить пользовательское хранилище файлов — например, хранить файлы в удалённой системе, — вы можете сделать это, определив пользовательский класс хранилища. Для этого выполните следующие шаги:
-
Ваша пользовательская система хранения должна быть подклассом
django.core.files.storage.Storage:from django.core.files.storage import Storage class MyStorage(Storage): ...
-
Django должен иметь возможность создавать экземпляр вашей системы хранения без аргументов. Это означает, что все настройки должны браться из
django.conf.settings:from django.conf import settings from django.core.files.storage import Storage class MyStorage(Storage): def __init__(self, option=None): if not option: option = settings.CUSTOM_STORAGE_OPTIONS ... -
Ваш класс хранилища должен реализовать методы
_open()и_save(), а также любые другие методы, подходящие для вашего класса хранилища. Подробнее об этих методах см. ниже.Кроме того, если ваш класс обеспечивает локальное файловое хранилище, он должен переопределить метод
path(). - Ваш класс хранилища должен быть деконструируемым, чтобы его можно было сериализовать при использовании в поле миграции. Если аргументы вашего поля сами по себе сериализуемы, для этого можно использовать декоратор класса
django.utils.deconstruct.deconstructible(именно его Django использует для FileSystemStorage).
По умолчанию следующие методы вызывают NotImplementedError, поэтому обычно их необходимо переопределить:
Однако обратите внимание, что не все эти методы обязательны, и некоторые из них можно намеренно не реализовывать. Как оказалось, можно оставить каждый метод нереализованным и при этом получить работающее хранилище.
Например, если перечисление содержимого некоторых хранилищ окажется затратным, можно решить не реализовывать Storage.listdir().
Другой пример — бэкенд, который обрабатывает только запись в файлы. В этом случае нет необходимости реализовывать ни один из перечисленных выше методов.
В конечном счёте решение о том, какие из этих методов реализовывать, остаётся за вами. Если некоторые методы не реализованы, интерфейс будет неполным и, возможно, неработоспособным.
Обычно также следует использовать хуки, специально предназначенные для пользовательских объектов хранилища. Это:
-
_open(name, mode='rb')
Обязательно.
Вызывается методом Storage.open() и представляет собой механизм, с помощью которого класс хранилища открывает файл. Метод должен возвращать объект File, хотя в большинстве случаев следует возвращать его подкласс, реализующий логику конкретного бэкенда хранилища. Если файл не существует, следует вызвать исключение FileNotFoundError.
-
_save(name, content)
Вызывается методом Storage.save(). Объект name уже прошёл через get_valid_name() и get_available_name(), а content сам будет объектом File.
Метод должен возвращать фактическое имя сохранённого файла (обычно это переданное значение name, но если хранилищу нужно изменить имя файла, верните новое имя).
-
get_valid_name(name)
Возвращает имя файла, подходящее для используемой системы хранения. Аргумент name, переданный этому методу, — это либо исходное имя файла, отправленное на сервер, либо, если upload_to является вызываемым объектом, имя файла, возвращённое этим методом после удаления сведений о пути. Переопределите этот метод, чтобы настроить преобразование нестандартных символов в безопасные имена файлов.
Код, предоставляемый в Storage, сохраняет в исходном имени файла только буквенно-цифровые символы, точки и символы подчёркивания, удаляя всё остальное.
-
get_alternative_name(file_root, file_ext)
Возвращает альтернативное имя файла на основе параметров file_root и file_ext. По умолчанию перед расширением к имени файла добавляется символ подчёркивания и случайная буквенно-цифровая строка из 7 символов.
-
get_available_name(name, max_length=None)
Возвращает имя файла, доступное в механизме хранения, при необходимости учитывая переданное имя. Аргумент name, переданный этому методу, уже очищен и представляет собой имя файла, допустимое для системы хранения согласно описанному выше методу get_valid_name().
Длина имени файла не будет превышать max_length, если этот параметр указан. Если не удаётся найти свободное уникальное имя файла, вызывается исключение SuspiciousFileOperation.
Если файл с именем name уже существует, вызывается get_alternative_name() для получения альтернативного имени.
Использование пользовательского механизма хранения
Чтобы использовать пользовательское хранилище в Django, сначала сообщите Django, какой бэкенд хранилища файлов вы будете использовать. Для этого служит настройка STORAGES. Эта настройка сопоставляет псевдонимы хранилищ — способ ссылаться на конкретное хранилище в Django — со словарём настроек для соответствующего бэкенда хранилища. Настройки во вложенных словарях подробно описаны в документации по STORAGES.
Затем доступ к хранилищам осуществляется по псевдониму через словарь django.core.files.storage.storages:
from django.core.files.storage import storages example_storage = storages["example"]
© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/6.0/howto/custom-file-storage/