使用Boto3上传到Amazon S3并返回公共网址

时间:2015-11-19 16:40:39

标签: django-models amazon-s3 boto3

我尝试使用Boto3将文件上传到s3并将上传的文件公开并将其作为网址返回。

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 
    })

我搜索了整个文档我找不到任何描述如何做到这一点的链接,有人可以解释或提供我可以找到灵魂的任何资源吗?

7 个答案:

答案 0 :(得分:29)

我处于同样的境地。 由于我有公共可读的S3对象,因此无法在generate_presigned_url之外的Boto3文档中找到任何我不需要的内容。

我想出的最好的是:

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)

您可以尝试在boto3 github issues list上发帖以获得更好的解决方案。

答案 1 :(得分:14)

我有同样的问题。 假设您知道要存储数据的存储桶名称,则可以使用以下命令:

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)

答案 2 :(得分:8)

我找到的最佳解决方案仍然是使用generate_presigned_url,只需将Client.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存储库的相关讨论是:

答案 3 :(得分:2)

某些人希望为公共可访问对象建立直接url以避免由于某种原因而使用generate_presigned_url

考虑到空格和特殊字符问题,请使用urllib.parse.quote_plus构建url。

  • 我的对象密钥:2018-11-26 16:34:48.351890+09:00.jpg 请注意空格和':'
  • aws控制台中的S3公共链接: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)

答案 4 :(得分:1)

通过现有的答案和他们的评论,我做了以下工作,并且适用于具有空格、具有特殊字符 (ASCII) 等特殊情况的文件名, 角落案例。例如。形式的文件名:“key=value.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)

答案 5 :(得分:0)

我用f弦代替

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"

答案 6 :(得分:-1)

对于Django,如果您将Django存储与boto3结合使用,则以下代码完全可以满足您的要求:

default_storage.url(name=f.name)