Хранилища¶
Файловая система¶
Самый часто используемый тип хранилища, не требующий установки дополнительных зависимостей.
Конструктор FileSystemStorage
принимает один обязательный аргумент dest
- путь к директории,
в которой будут сохраняться загруженные файлы.
Значение может быть:
абсолютным путем;
относительным путем с обязательной опцией
UPLOADER_ROOT_DIR
, тогда абсолютный путь рассчитывается как{UPLOADER_ROOT_DIR}/{dest}
;относительным путем с включенной опцией
UPLOADER_INSTANCE_RELATIVE_ROOT
, тогда абсолютный путь рассчитывается как<instance_folder>/{dest}
;относительным путем с включенной опцией
UPLOADER_INSTANCE_RELATIVE_ROOT
и не пустым значением опцииUPLOADER_ROOT_DIR
, тогда абсолютный путь рассчитывается как<instance_folder>/{UPLOADER_ROOT_DIR}/{dest}
.
Пример №1:
>>> from flask import Flask
>>> from flask_uploader.storages import FileSystemStorage
>>> app = Flask(__name__)
>>> app.config['UPLOADER_ROOT_DIR'] = '/app/uploads/'
>>> files_storage = FileSystemStorage(dest='files')
>>> files_storage.get_root_dir()
'/app/uploads/files'
Пример №2:
>>> from flask import Flask
>>> from flask_uploader.storages import FileSystemStorage
>>> app = Flask(__name__, instance_path='/app/instance') # for example
>>> app.config['UPLOADER_ROOT_DIR'] = 'uploads'
>>> app.config['UPLOADER_INSTANCE_RELATIVE_ROOT'] = True
>>> files_storage = FileSystemStorage(dest='files')
>>> files_storage.get_root_dir()
'/app/instance/uploads/files'
Рекомендуется избегать общих директорий для разных экземпляров хранилищ, Это защитит вас от случайной перезаписи, удаления или несанкционированного доступа к файлам другими загрузчиками или хранилищами. Например:
uploads
└── files
├── books
└── photos
from flask import Flask
from flask_uploader.storages import FileSystemStorage
# Good practice
books_storage = FileSystemStorage(dest='files/books')
photos_storage = FileSystemStorage(dest='files/photos')
# Bad practice, has access to files from other storages.
files_storage = FileSystemStorage(dest='files')
MongoDB GridFS¶
Из документации:
GridFS - это спецификация для хранения и извлечения файлов, размер которых превышает предельный размер документа BSON равный 16Mb.
Flask-Uploader
использует расширение Flask-Pymongo,
поэтому все доступные конфигурационные параметры смотрите в их документации.
Чтобы использовать GridFS неоходимо установить дополнительные зависимости:
pip install 'Flask-Uploader[pymongo]'
Затем создайте новый экземпляр хранилища на основе класса
GridFSStorage
.
Конструктор принимает два обязательных аргумента:
экземпляр расширения PyMongo
и имя коллекции для сохранения файлов:
from flask_pymongo import PyMongo
from flask_uploader.contrib.pymongo import GridFSStorage
mongo = PyMongo()
books_storage = GridFSStorage(mongo, 'books')
Рекомендуется использовать разные коллекции для разных экземпляров хранилищ. Это защитит вас от случайной перезаписи, удаления или несанкционированного доступа к файлам другими загрузчиками или хранилищами.
Перезапись файла¶
Из документации:
Не используйте GridFS, если вам нужно обновить содержимое всего файла атомарно. В качестве альтернативы вы можете хранить несколько версий каждого файла и указывать текущую версию в метаданных после загрузки новой версии файла, а затем, при необходимости, удалить предыдущие версии.
GridFSStorage
не использует версионирование.
Если метод save()
вызывается с аргументом overwrite
равным False
, то для файла генерируется новое имя.
Если метод save()
вызывается с аргументом overwrite
равным True
, то существующий файл удаляется
и создается новый с точно таким же первичным ключом.
ObjectId¶
Метод save()
возвращает не обычную строку,
а специальный тип Lookup
, унаследованный от str
.
Чтобы получить идентификатор сохраненного файла, обратитесь к свойству oid
:
lookup = books_uploader.save(request.files['file'], overwrite=True)
mongo.db.books.insert_one({
'title': request.form['title'],
'file': lookup.oid,
})
Amazon S3¶
Flask-Uploader
использует официальный SDK Boto3 и реализует встроенное расширение Flask-AWS:
AWS
.
Вы можете использовать любой облачный сервис, совместимый с API Amazon, например Yandex.Cloud.
Следующие конфигурационные опции сессии доступны для установки:
Опция |
Описание |
---|---|
AWS_ACCESS_KEY_ID |
Идентификатор ключа доступа AWS.
По-умолчанию |
AWS_SECRET_ACCESS_KEY |
Секретный ключ доступа AWS.
По-умолчанию |
AWS_AWS_SESSION_TOKEN |
Временный токен сеанса AWS.
По-умолчанию |
AWS_REGION_NAME |
Регион по умолчанию при создании новых подключений.
По-умолчанию |
AWS_PROFILE_NAME |
Имя используемого профиля.
Если не задан, используется профиль по умолчанию.
По-умолчанию |
Следующие конфигурационные опции доступны для низкоуровневых клиентов, либо для ресурсов.
Значения опций можно задавать глобально для всех клиентов и ресурсов, тогда имена опций совпадают с именами, указанными в таблице ниже.
Либо указать опцию для конкретного сервиса, например облачного хранилища S3
,
тогда имена опций указываются по шаблону: AWS_<service_name>_<option_name>
,
например AWS_S3_ENDPOINT_URL
:
Опция |
Описание |
---|---|
AWS_API_VERSION |
Используемая версия API.
По умолчанию используется последняя версия.
Вам нужно указать этот параметр только в том случае,
если вы хотите использовать предыдущую версию API.
По-умолчанию |
AWS_USE_SSL |
Использовать SSL или нет.
По умолчанию используется SSL.
Обратите внимание,
что не все сервисы поддерживают подключения без SSL.
По-умолчанию |
AWS_VERIFY |
Проверять или нет SSL-сертификаты.
По умолчанию SSL-сертификаты проверяются.
По-умолчанию |
AWS_ENDPOINT_URL |
Полный URL-адрес (включая схему |
Чтобы использовать облачное хранишище S3 неоходимо установить дополнительные зависимости:
pip install 'Flask-Uploader[aws]'
Затем создайте новый экземпляр хранилища на основе класса
S3Storage
.
Конструктор принимает два обязательных аргумента:
экземпляр ресурса S3
, который можно создать с помощью метода расширения
resource()
и имя корзины для сохранения файлов:
from flask_uploader.contrib.aws import AWS, S3Storage
aws = AWS()
storage = S3Storage(
aws.resource('s3'),
'flask-uploader',
)
Если вы хотите использовать одну корзину для разных экземпляров
S3Storage
,
то рекомендуется задать уникальный префикс для ключей
и избегать более общих префиксов для разных экземпляров хранилищ,
Это защитит вас от случайной перезаписи, удаления или несанкционированного доступа к файлам
другими загрузчиками или хранилищами:
from flask_uploader.contrib.aws import AWS, S3Storage
aws = AWS()
storage = S3Storage(
aws.resource('s3'),
'flask-uploader',
key_prefix='files',
)
Имя файла¶
Оригинальное имя загруженного файла не используется при сохранении. Новое имя должна вернуть стратегия - это вызываемый объект, который в качестве единственного аргумента принимает загруженный файл и возвращает новое имя.
# Source code from Flask-Uploader
import typing as t
from werkzeug.datastructures import FileStorage
TFilenameStrategy = t.Callable[[FileStorage], str]
По-умолчанию используется HashedFilenameStrategy
,
которая генерирует имя, вычисляя хэш содержимого файла и разбивая его на указанное количество частей указанной длины.
Она решает проблему хранения большого количества файлов на жестком диске,
когда количество файлов в одном каталоге ограничено ОС.
Благодаря хешу и разбиению файлы равномерно хранятся в каталогах.
Новая стратегия¶
Вы можете реализовать абсолютно любую стратегию для генерации имени, например, пусть имя сохраняемого файла будет текущей датой и временем:
from uuid import uuid4
from werkzeug.datastructures import FileStorage
def uuid_strategy(storage: FileStorage) -> str:
return str(uuid4())
В момент создания экземпляра хранилища в конструктор передайте аргумент filename_strategy
:
from flask_uploader.storages import FileSystemStorage
storage = FileSystemStorage(
dest='files',
filename_strategy=uuid_strategy
)
Метод save()
перед сохранением проверит:
что сгенерированное имя не пустая строка, иначе выбросит исключение
InvalidLookup
;что сгенерированное имя имеет расширение, иначе добавит его автоматически;
что файл существует и если явно не передан аргумент
overwrite
, добавит к имени суффикс_N
(изменить суффикс нельзя).
Это верно для любой стратегии.