Как написать собственный класс хранилища¶
Если вам необходимо предоставить собственное хранилище файлов — типичным примером является хранение файлов удаленно — вы можете сделать это, определив пользовательский класс хранилища. Для этого вам нужно будет выполнить следующие шаги:
Ваше собственное хранилище должно быть подклассом
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 ...
Your storage class must implement the
_open()and_save()methods, along with any other methods appropriate to your storage class. See below for more on these methods.Кроме того, если ваш класс предоставляет локальное хранилище файлов, он должен переопределить метод
path().Your storage class must be deconstructible so it can be serialized when it’s used on a field in a migration. As long as your field has arguments that are themselves serializable, you can use the
django.utils.deconstruct.deconstructibleclass decorator for this (that’s what Django uses on FileSystemStorage).
По-умолчанию следующие методы вызывают NotImplementedError и должны быть переопределены:
Однако следует отметить, что не все эти методы являются обязательными и могут быть пропущены. Можно оставить каждый метод нереализованным, и хранилище все равно будет работать.
В качестве примера, если перечисление содержимого определенных бэкэндов хранилищ окажется сложным и затратным в плане ресурсов, вы можете решить не реализовывать Storage.listdir().
Другим примером может служить бэкэнд, который делает только запись в файлы. В этом случае вам не нужно будет реализовывать ни один из вышеперечисленных методов.
В конечном счете, какой из этих методов реализовать, решать вам. Если оставить некоторые методы нереализованными, то это приведет к работоспособности хранилища (а может, оно будет сломано).
Вы также, может быть, захотите использовать хуки, специально разработанные для пользовательских хранилищ файлов. Вот они:
- _open(name, mode='rb')¶
Required.
Вызывается 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. По умолчанию к имени файла перед расширением добавляется подчеркивание и случайная строка из семи символов, состоящая из букв и цифр.
- 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 dictionary:
from django.core.files.storage import storages
example_storage = storages["example"]