【问题标题】:Django and S3 direct uploadsDjango 和 S3 直接上传
【发布时间】:2015-10-18 20:05:28
【问题描述】:

在我的项目中,我已配置并正常工作 S3 storages 。现在我正在尝试使用s3 direct 配置直接上传到s3。它几乎可以正常工作。用户可以上传图像并将其存储在 S3 中。当我在数据库中保存对图像的引用时,问题就来了。

models.py

class FullResPicture(Audit):
    docfile = models.ImageField()
    picture = models.OneToOneField(Picture, primary_key=True)

settings.py

...
S3DIRECT_DESTINATIONS = {
    # Allow anybody to upload jpeg's and png's.
    'imgs': ('uploads/imgs', lambda u: u.is_authenticated(), ['image/jpeg', 'image/png'], 'public-read','bucket-name'),
}
...

views.py

#Doc file is the url to the image that the user uploaded directly to S3
#https://s3-eu-west-1.amazonaws.com/bucket/uploads/imgs/picture.jpeg
fullRes = FullResPicture(docfile = form_list[1].cleaned_data['docfile'])

所以,如果我查看我的数据库,我会发现一些工作正常的图片(那些我只使用 django-storages 上传的图片)具有如下 docfile 值:

images/2015/08/11/image.jpg

当应用程序尝试访问这些图像时,S3 boto 能够正确获取图像。

但是我已经直接从用户的浏览器上传了图片。对于那些,我存储了完整的 url,所以它们在数据库中看起来像这样:

https://s3-eu-west-1.amazonaws.com/bucket/uploads/imgs/Most-Famous-Felines-034.jpg

当应用程序尝试访问它们时,我遇到了这个异常:

File "/Users/mariopersonal/Documents/dev/venv/pictures/lib/python2.7/site-packages/django/db/models/fields/files.py", line 49, in _get_file
    self._file = self.storage.open(self.name, 'rb')
  File "/Users/mariopersonal/Documents/dev/venv/pictures/lib/python2.7/site-packages/django/core/files/storage.py", line 35, in open
    return self._open(name, mode)
  File "/Users/mariopersonal/Documents/dev/venv/pictures/lib/python2.7/site-packages/storages/backends/s3boto.py", line 363, in _open
    name = self._normalize_name(self._clean_name(name))
  File "/Users/mariopersonal/Documents/dev/venv/pictures/lib/python2.7/site-packages/storages/backends/s3boto.py", line 341, in _normalize_name
    name)
SuspiciousOperation: Attempted access to 'https:/s3-eu-west-1.amazonaws.com/bucket/uploads/imgs/Most-Famous-Felines-034.jpg' denied.

显然,S3 boto 不喜欢将文件引用作为完整的 url。

出于故障排除的目的,我尝试对保存的值进行硬编码,因此它只保存最后一部分而不是完整的 url,但是当它尝试访问图像时,我遇到了另一个异常:

IOError: File does not exist: uploads/imgs/Most-Famous-Felines-034.jpg

有人知道这里出了什么问题吗?有没有人有任何直接上传到 s3 的工作示例,它将对上传文件的引用存储在模型中?

谢谢。

【问题讨论】:

    标签: python django amazon-s3 boto3


    【解决方案1】:

    这是我修复的方式,以防它帮助其他人。 此解决方案适用,如果您已经让 django-storages 正常工作 django-s3direct 从客户端上传图像但您无法让它们一起工作。

    使用同一个桶

    我做的第一件事是确保 django-storages 和 django-s3direct 都配置为使用相同的存储桶。由于您已经让 django-storages 和 django-s3direct 分别工作,因此只需检查两者是否使用相同的存储桶。对于大多数用户来说,只需要这样做:

    settings.py

    ...
    S3DIRECT_DESTINATIONS = {
        # Allow anybody to upload jpeg's and png's.
        'imgs': ('uploads/imgs', lambda u: u.is_authenticated(), ['image/jpeg', 'image/png'], 'public-read', AWS_STORAGE_BUCKET_NAME),
    }
    ...
    

    请注意,我们使用的是AWS_STORAGE_BUCKET_NAME,应该为 django-storages 配置定义。

    在我的情况下稍微复杂一点,因为我为不同的模型使用不同的存储桶。

    只存储密钥

    当使用 s3-direct 时,一旦用户上传了图片并提交了表单,我们的视图就会收到 S3 放置图片的 url。如果我们存储这个 url,当 s3-storages 尝试访问该图像时,它不会起作用,所以我们要做的就是只存储文件的密钥。

    文件的键是存储桶内图像的路径。例如,对于 url https://s3-eu-west-1.amazonaws.com/bucket/uploads/imgs/Most-Famous-Felines-034.jpgkeyuploads/imgs/Most-Famous-Felines-034.jpg,所以这是我们需要存储在模型中的值。在我的情况下,我使用这个 sn-p 从 url 中提取密钥:

    def key_from_url(url, bucket):
        try:
            indexOf = url.index(bucket)
            return url[indexOf:]
        except:
            raise ValueError('The url provided does not match the bucket name')
    

    一旦我进行了这些更改,它就会无缝运行。 我希望这对处于相同情况的任何人都有帮助。

    【讨论】:

    • 我遇到了 django-storages 和 django-s3direct 使用 AWS_ENDPOINT_URL 不同的问题。我保留该常量来设置 django-s3direct,但我将 s3boto3storages 子类化以设置 endpoint_url 类变量,以便 django-storages 可以正常工作。问题是 django-storages 将存储桶名称添加到我的键中,因此 django-storages 在 <bucket>.s3.amazonaws.com/<bucket>/<key> 中查找项目而不是 <bucket>.s3.amazonaws.com/<key>
    猜你喜欢
    • 2012-03-14
    • 2018-12-15
    • 2019-04-05
    • 2014-06-24
    • 2018-09-13
    • 2011-05-12
    • 1970-01-01
    • 2020-11-14
    • 2011-09-01
    相关资源
    最近更新 更多