Переход с Client-Django-S3 загрузки изображений/файлов на Client-S3 загрузку URL с предварительной подписью, сохраняя FileField/ImageField?
Текущее состояние нашего приложения следующее: Клиент делает POST-запрос на наш сервер приложений Django + DRF с одним или несколькими файлами, сервер django обрабатывает файлы, затем загружает и сохраняет их на S3. Это делается с помощью замечательных библиотек django-storages & boto3. В конечном итоге мы будем иметь ссылку url на наши файлы S3 в нашей Базе Данных.
Очень упрощенный пример выглядит следующим образом:
# models.py
class TestImageModel(models.Model):
image = models.ImageField(upload_to='<path_in_bucket>', storage=S3BotoStorage())
# serializers.py
class TestImageSerializer(serializers.ModelSerializer):
image = serializers.ImageField(write_only=True)
Библиотека storages обрабатывает загрузку на S3 и вызывает что-то вроде:
TestImageModel.objects.first().image.url
вернет ссылку на url изображения в S3 (технически в нашем случае это будет URL cloudfront, так как мы используем его как CDN, и установили custom_domain в классе S3BotoStorage)
Таков был первоначальный подход, но мы заметили большой расход памяти сервера из-за того, что изображения сначала загружаются на наш сервер, а затем снова загружаются на S3. Для эффективного масштабирования мы хотели бы перейти к подходу, при котором вместо этого изображения загружаются непосредственно с клиента на S3 с помощью заранее назначенных URL. Я нашел документацию о том, как это сделать, здесь: https://boto3.amazonaws.com/v1/documentation/api/latest/guide/s3-presigned-urls.html.
Новая стратегия, которую я приму для загрузки изображений:
- Client requests Presigned url from Django API
- Client uploads to S3 directly
- Django updates reference to uploaded image in database with ImageField.
Мой вопрос касается 3). Как я могу сказать django record, что уже загруженное изображение в S3 должно быть местоположением ImageField, без необходимости повторной загрузки изображения через класс S3BotoStorage?
Альтернативой может быть изменение ImageField на URLField, и просто хранить ссылку нового изображения, но это не позволит мне использовать возможности ImageField (Forms в админке django, удаление непосредственно из S3 с помощью класса хранения .delete(), и т.д.).
Как я могу обновить ImageField, чтобы он указывал на существующий файл в том же хранилище, или есть лучший способ перейти к стратегии прямой загрузки Client-S3 с Django и ImageField?
Итак, очевидно, что вы можете просто сделать что-то вроде этого:
a = TestImageModel.objects.first()
a.image.name = 'path_to_image'
a.save()
И все прекрасно работает :)