Writing a custom storage system¶
Если вам необходимо предоставить собственное хранилище файлов — типичным примером является хранение файлов удаленно — вы можете сделать это, определив пользовательский класс хранилища. Для этого вам нужно будет выполнить следующие шаги:
Ваше собственное хранилище должно быть подклассом
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')¶
Required.
Called by Storage.open(), this is the actual mechanism the storage class
uses to open the file. This must return a File object, though in most cases,
you’ll want to return some subclass here that implements logic specific to the
backend storage system.
- _save(name, content)¶
Вызывается Storage.save(). name уже прошло через get_valid_name() и get_available_name(), а content будет объектом File.
Should return the actual name of name of the file saved (usually the name
passed in, but if the storage needs to change the file name return the new name
instead).
- 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() для получения альтернативного имени.