在我的项目中,我已经配置并正常工作S3 storages。现在我正在尝试使用s3 direct配置直接上传到s3。它工作得很好。用户能够上传图像并将其存储在S3中。当我将DB中的引用保存到图像时出现问题。
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上传的图像),其文档文件值如下:
images/2015/08/11/image.jpg
当应用程序尝试访问这些图像时,S3 boto能够正确获取图像。
但后来我直接从用户的浏览器上传了这些图片。对于那些,我存储完整的URL,所以它们在DB中看起来像这样:
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,但是当它试图访问图像时我遇到了另一个异常:
IOError: File does not exist: uploads/imgs/Most-Famous-Felines-034.jpg
有人知道这里出了什么问题吗?有没有人有任何直接上传到s3的工作示例,它存储模型中对上传文件的引用?
感谢。
答案 0 :(得分:2)
这是我修复的方式,以防它帮助其他人。 此解决方案适用如果您已经django-storages正常工作django-s3direct从客户端上传图片,但无法让它们协同工作。
我做的第一件事就是确保django-storage和django-s3direct都配置为使用相同的存储桶。由于您已经将django-storage和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-storage尝试访问图像时,它将无法工作,因此我们要做的只是存储文件的密钥。
文件的键是存储桶内图像的路径。例如,对于网址 https://s3-eu-west-1.amazonaws.com/bucket/uploads/imgs/Most-Famous-Felines-034.jpg
,密钥为uploads/imgs/Most-Famous-Felines-034.jpg
,因此这是我们需要存储在模型上的值。在我的情况下,我正在使用此代码段从网址中提取密钥:
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')
一旦我做出这些改变,它就能无缝地工作。 我希望这可以帮助处于相同情况的任何人。