Как смешать Django, Uploadify и S3Boto Storage Backend?
Фон
Я делаю довольно большие загрузки файлов на Django. Размер файла обычно составляет от 10 до 100 МБ.
Я на Heroku, и у меня истекло время ожидания запроса 30 секунд.
Начало
Чтобы обойти ограничение, рекомендуется Heroku загружать из браузера ПРЯМО на S3.
Amazon документирует это, показывая вам, как написать HTML-форму для выполнения загрузки.
Поскольку я использую Django, а не пишу HTML вручную, я использую https://github.com/sbc/django-uploadify-s3 ( пример). Это предоставляет мне SWF-объект, завернутый в JS, который выполняет фактическую загрузку.
Эта часть работает нормально! Ура!
Эта проблема
Проблема заключается в том, чтобы связать эти данные обратно с моей моделью Django. Прямо сейчас данные возвращаются в виде простой строки URL, указывающей на местоположение файла.
Однако ранее я использовал S3 Boto из django-хранилищ для управления всеми своими файлами как FileFields
при поддержке восхитительного S3BotoStorageFile
,
Напомним, что S3 Boto отлично работает в изоляции, Uploadify прекрасно работает в изоляции, проблема в том, чтобы соединить их вместе.
Я понимаю, что единственный способ заселить FileField
путем предоставления как имени файла, так и содержимого файла. Когда вы загружаете файлы из браузера в Django, это не проблема, поскольку Django хранит содержимое файла в буфере и может делать с ним все что угодно. Однако, когда я выполняю прямую загрузку на S3, как я, Django получает только имя файла и URL, а не двоичные данные, поэтому я не могу правильно заполнить FieldFile
,
Молить о помощи
Кто-нибудь знает изящный способ использования FileField от S3Boto в сочетании с прямой загрузкой на S3?
Иначе, как лучше всего управлять файлом S3 только по его URL? В том числе установка срока действия, идентификатор ключа и т. Д.
Большое спасибо!
6 ответов
У меня была похожая проблема, когда я хочу сохранить файл на s3 либо напрямую, используя FileField, либо у меня есть возможность для пользователя ввести URL-адрес напрямую. Поэтому, чтобы обойти это, я использовал 2 поля в моей модели, одно для FileField и одно для URLField. И в шаблоне я мог бы использовать 'или', чтобы увидеть, какой из них существует, и использовать его как {{ instance.filefield или instance.url }}.
Это не проверено, но вы должны быть в состоянии использовать:
from django.core.files.storage import default_storage
f = default_storage.open('name_you_expect_in_s3', 'r')
#f is an instance of S3BotoStorageFile, and can be assigned to a field
obj, created = YourObject.objects.get_or_create(**stuff_you_know)
obj.s3file_field = f
obj.save()
Я думаю, что это должно установить локальный указатель на s3 и сохранить его, не перезаписывая содержимое.
ETA: Вы должны сделать это только после завершения загрузки на S3, и вы знаете ключ в s3.
Оформить заказ на django-filetransfers. Похоже, это хорошо сочетается с Django-хранилищами.
Я никогда не использовал django, так что ymmv:), но почему бы просто не написать один байт для заполнения контента? Таким образом, вы все еще можете использовать FieldFile.
Я думаю, что написание реального SQL может быть самым простым решением здесь. В качестве альтернативы вы можете создать подкласс S3BotoStorage, переопределить метод _save и разрешить дополнительный kwarg filepath, который обходит все остальные элементы сохранения и просто возвращает cleaned_name.