Создание пользовательской системы хранения
Если вам нужно предоставить пользовательское хранилище файлов — распространённый пример — хранение файлов на какой-либо удалённой системе — вы можете сделать это, определив пользовательский класс хранилища. Вам нужно выполнить эти шаги:
-
Ваша пользовательская система хранения должна быть подклассом
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, хотя в большинстве случаев вы захотите вернуть здесь какой-либо подкласс, который реализует логику, специфичную для системы хранения бэкэнда.
-
_save(name, content)
Вызывается Storage.save(). name уже пройдёт через get_valid_name() и get_available_name(), а content будет самим объектом File.
Должно вернуть фактическое имя сохранённого файла (обычно имя name , переданное в него, но если хранилищу нужно изменить имя файла, то вместо этого верните новое имя).
-
get_valid_name(name)
Возвращает имя файла, подходящее для использования с системой хранения. Аргумент name , переданный в этот метод, — это исходное имя файла после удаления любой информации о пути. Переопределите этот метод, чтобы настроить преобразование нестандартных символов в безопасные имена файлов.
Представленный на Storage код сохраняет только буквенно-цифровые символы, точки и подчёркивания из исходного имени файла, удаляя всё остальное.
-
get_available_name(name, max_length=None)
Возвращает имя файла, доступное в механизме хранения, возможно, с учётом переданного имени файла. Аргумент name , переданный в этот метод, уже очищен до имени файла, пригодного для системы хранения, в соответствии с методом get_valid_name() , описанным выше.
Длина имени файла не будет превышать max_length, если предоставлено. Если свободный уникальный файл не может быть найден, возникает исключение SuspiciousFileOperation.
Если файл с name уже существует, к имени файла перед расширением добавляется знак подчёркивания и случайная 7-символьная буквенно-цифровая строка.
Ранее к имени файла добавлялся знак подчёркивания, за которым следовали цифры (например, "_1", "_2", и т. д.) до тех пор, пока не находилось доступное имя в целевом каталоге. Злоумышленник мог использовать этот детерминированный алгоритм для создания атаки с отказом в обслуживании. Это изменение также было внесено в Django 1.6.6, 1.5.9 и 1.4.14.
Аргумент max_length был добавлен.
© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/1.8/howto/custom-file-storage/