Загрузите в Amazon S3 с помощью Boto3 и верните общедоступный URL

Я пытаюсь загрузить файлы на s3 с помощью Boto3, сделать этот загруженный файл общедоступным и вернуть его как URL-адрес.

class UtilResource(BaseZMPResource):
class Meta(BaseZMPResource.Meta):
    queryset = Configuration.objects.none()
    resource_name = 'util_resource'
    allowed_methods = ['get']

def post_list(self, request, **kwargs):

    fileToUpload = request.FILES
    # write code to upload to amazone s3
    # see: https://boto3.readthedocs.org/en/latest/reference/services/s3.html


    self.session = Session(aws_access_key_id=settings.AWS_KEY_ID,
                  aws_secret_access_key=settings.AWS_ACCESS_KEY,
                  region_name=settings.AWS_REGION)

    client = self.session.client('s3')
    client.upload_file('zango-static','fileToUpload')


    url = "some/test/url"
    return self.create_response(request, {
        'url': url // return's public url of uploaded file 
    })

Я просмотрел всю документацию, я не смог найти никаких ссылок, описывающих, как это сделать, может кто-нибудь объяснить или предоставить какой-либо ресурс, где я могу найти душу?


person Yaswanth Kumar    schedule 19.11.2015    source источник
comment
Где можно заставить это работать?   -  person nadermx    schedule 12.12.2015
comment
@nadermx Мне не удалось получить эту работу, вы можете мне помочь?   -  person Yaswanth Kumar    schedule 13.12.2015
comment
Используйте виртуальные URL-адреса S3 в стиле: stackoverflow.com/a/56090535/795876   -  person fsenart    schedule 11.05.2019


Ответы (7)


Я в такой же ситуации. Невозможно найти что-либо в документации Boto3, кроме generate_presigned_url, что мне не нужно в моем случае, поскольку у меня есть общедоступные читаемые объекты S3.

Лучшее, что я придумал:

bucket_location = boto3.client('s3').get_bucket_location(Bucket=s3_bucket_name)
object_url = "https://s3-{0}.amazonaws.com/{1}/{2}".format(
    bucket_location['LocationConstraint'],
    s3_bucket_name,
    key_name)

Вы можете попробовать опубликовать сообщение в списке проблем github с boto3 для лучшего решения.

person Sam Keen    schedule 09.01.2016
comment
Оказывается, мне не нужен регион в URL-адресе. https://s3.amazonaws.com/my_bucket/my_file.jpg работал у меня. - person The Unknown Dev; 28.03.2018
comment
@KimberlyW это потому, что регион вашего актива - US-EAST1 docs.aws.amazon.com/general/latest/gr/rande.html#s3_region - person Curtis W; 02.01.2019
comment
Этот ответ не работает, если файл, например, содержит пробелы и не ascii. - person Uri Merhav; 27.03.2019
comment
этот ответ также не работает для интеграционных тестов с локальным стеком. - person rahimli; 06.11.2020

Я была такая же проблема. Предполагая, что вы знаете имя сегмента, в котором хотите хранить свои данные, вы можете использовать следующее:

import boto3
from boto3.s3.transfer import S3Transfer

credentials = { 
    'aws_access_key_id': aws_access_key_id,
    'aws_secret_access_key': aws_secret_access_key
}

client = boto3.client('s3', 'us-west-2', **credentials)
transfer = S3Transfer(client)

transfer.upload_file('/tmp/myfile', bucket, key,
                     extra_args={'ACL': 'public-read'})

file_url = '%s/%s/%s' % (client.meta.endpoint_url, bucket, key)
person Eron Castro    schedule 21.10.2016
comment
Спасибо, extra_args в upload_file с использованием S3Transfer - это то, что мне нужно было использовать вместе при создании клиента через сеанс для настраиваемых конечных точек. - person madprops; 01.11.2017
comment
как загрузить объект файла - person pyd; 30.11.2019
comment
@pyd см. это = ›stackoverflow.com/a/51758077/9183715 - person Noman Gul; 17.11.2020
comment
@NomanGul эта ссылка не объясняет, как загрузить объект в память и сгенерировать из него общедоступный URL - person fedest; 22.04.2021

Лучшее решение, которое я нашел, - это использовать generate_presigned_url, только для Client.Config.signature_version нужно установить значение botocore.UNSIGNED.

Следующее возвращает общедоступную ссылку без подписи.

config = Config(signature_version=botocore.UNSIGNED)
config.signature_version = botocore.UNSIGNED
boto3.client('s3', config=config).generate_presigned_url('get_object', ExpiresIn=0, Params={'Bucket': bucket, 'Key': key})

Соответствующие обсуждения репозитория boto3:

person wonton    schedule 10.01.2018
comment
Это должен быть принятый ответ. Тот же острый ответ прерывается, если имя файла содержит, например, пробелы, а затем эвристика key_name = object_url с некоторыми префиксами прерывается. - person Uri Merhav; 27.03.2019
comment
Но у него короткий срок действия. Максимум всего 7 дней, а для СТС короче. - person seuling; 19.07.2019
comment
Для большей ясности ответу лучше показать, откуда берется конфиг. Пример: config = Config(signature_version=botocore.UNSIGNED) url = s3_session.client('s3', config=config).generate_presigned_url( ClientMethod='get_object', ExpiresIn=0, Params={'Bucket': bucket_name, 'Key': key} ) - person Alexandre Assouad; 18.11.2019
comment
Отредактированный ответ с вашим предложением - person wonton; 19.11.2019

Кто-то, кто хочет создать прямой URL-адрес для общедоступного объекта, чтобы по какой-то причине избегать использования generate_presigned_url.

Пожалуйста, создайте URL с urllib.parse.quote_plus с учетом пробелов и специальных символов.

  • Ключ моего объекта: 2018-11-26 16:34:48.351890+09:00.jpg обратите внимание на пробелы и ":"
  • Публичная ссылка S3 в консоли AWS: https://s3.my_region.amazonaws.com/my_bucket_name/2018-11-26+16%3A34%3A48.351890%2B09%3A00.jpg

Код ниже был в порядке для меня

import boto3    
s3_client = boto3.client
bucket_location = s3_client.get_bucket_location(Bucket='my_bucket_name')
url = "https://s3.{0}.amazonaws.com/{1}/{2}".format(bucket_location['LocationConstraint'], 'my_bucket_name', quote_plus('2018-11-26 16:34:48.351890+09:00.jpg')
print(url)
person Jay Lim    schedule 26.11.2018

Просматривая существующие ответы и комментарии к ним, я сделал следующее и хорошо работает для особых случаев имен файлов, таких как пробелы, специальные символы (ASCII), угловые шкафы. Например. имена файлов в форме: ключ = значение.txt

import boto3
import botocore

config = botocore.client.Config(signature_version=botocore.UNSIGNED)
object_url = boto3.client('s3', config=config).generate_presigned_url('get_object', ExpiresIn=0, Params={'Bucket': s3_bucket_name, 'Key': key_name})
print(object_url)
person Ankit Shubham    schedule 24.02.2021

Для Django, если вы используете хранилища Django с boto3, приведенный ниже код делает именно то, что вы хотите:

default_storage.url(name=f.name)
person Sebastian Brestin    schedule 10.07.2018

Я использовал ф-струну для того же

import boto3    
#s3_client = boto3.session.Session(profile_name='sssss').client('s3')
s3_client=boto3.client('s3')
s3_bucket_name = 'xxxxx'
s3_website_URL= f"http://{s3_bucket_name}.s3-website.{s3_client.get_bucket_location(Bucket=s3_bucket_name)['LocationConstraint']}.amazonaws.com"
person Dheeraj    schedule 04.09.2020