Написание пользовательской системы хранения

Если вам необходимо обеспечить пользовательское хранение файлов - распространенным примером является хранение файлов на какой-либо удаленной системе - вы можете сделать это, определив пользовательский класс хранения. Вам нужно будет выполнить следующие шаги:

  1. Ваша пользовательская система хранения должна быть подклассом django.core.files.storage.Storage:

    from django.core.files.storage import Storage
    
    class MyStorage(Storage):
        ...
    
  2. 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
            ...
    
  3. Ваш класс хранения должен реализовать методы _open() и _save(), а также любые другие методы, подходящие для вашего класса хранения. Подробнее об этих методах см. ниже.

    Кроме того, если ваш класс обеспечивает локальное хранение файлов, он должен переопределить метод path().

  4. Ваш класс хранилища должен быть deconstructible, чтобы его можно было сериализовать, когда он используется для поля в миграции. Пока ваше поле имеет аргументы, которые сами по себе serializable, вы можете использовать для этого декоратор класса 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, передаваемый этому методу, является либо исходным именем файла, отправленным на сервер, либо, если 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() для получения альтернативного имени.

Вернуться на верх