如何动态选择models.FileField的存储选项? [英] How to dynamically select storage option for models.FileField?
问题描述
取决于文件扩展名,我希望将文件存储在特定的AWS存储桶中.我尝试将函数传递给storage
选项,类似于动态定义upload_to
的方式.
Depending on the file extension, I want the file to be stored in a specific AWS bucket. I tried passing a function to the storage
option, similar to how upload_to
is dynamically defined.
但是,这不能获得理想的结果.在我的模板中,当我尝试href为document.docfile.url时,该链接不起作用.
However, this doesn't give the desired results. In my template, when I try href to document.docfile.url, the link doesn't work.
在外壳中检查,这会发生
Checking in the shell, this happens
Document.objects.all()[0].docfile.storage.bucket
<Bucket: <function aws_bucket at 0x110672050>>
Document.objects.all()[0].docfile.storage.bucket_name
<function myproject.myapp.models.aws_bucket>
期望的行为是
Document.objects.all()[0].docfile.storage.bucket_name
'asynch-uploader-txt'
Document.objects.all()[0].docfile.storage.bucket
<Bucket: asynch-uploader-txt>
这是我的models.py
文件:
# -*- coding: utf-8 -*-
from django.db import models
from storages.backends.s3boto import S3BotoStorage
def upload_file_to(instance, filename):
import os
from django.utils.timezone import now
filename_base, filename_ext = os.path.splitext(filename)
return 'files/%s_%s%s' % (
filename_base,
now().strftime("%Y%m%d%H%M%S"),
filename_ext.lower(),
)
def aws_bucket(instance, filename):
import os
filename_base, filename_ext = os.path.splitext(filename)
return 'asynch-uploader-%s' %(filename_ext[1:])
class Document(models.Model):
docfile = models.FileField(upload_to=upload_file_to,storage=S3BotoStorage(bucket=aws_bucket))
为什么aws_bucket
作为函数而不是字符串作为upload_file_to
的方式传递?我该如何纠正?
Why is aws_bucket
getting passed as a function and not a string, the way that upload_file_to
is? How can I correct it?
推荐答案
对于您要尝试做的事情,最好做一个自定义的存储后端,而只是覆盖S3BotoStorage的各个部分.
特别是,如果将bucket_name
设置为属性,则应该能够获得所需的行为.
For what you're trying to do you may be better off making a custom storage backend and just overriding the various bits of S3BotoStorage.
In particular if you make bucket_name
a property you should be able to get the behavior you want.
要对此进行扩展, S3BotoStorage.__init__
的source 具有bucket
作为可选参数.此外,在存储桶中使用时, class是一个@param
,使其易于覆盖.以下代码未经测试,但足以为您提供一个起点
To expand a bit on that, the source for S3BotoStorage.__init__
has the bucket
as an optional argument. Additionally bucket when it's used in the class is a @param
, making it easy to override. The following code is untested, but should be enough to give you a starting point
class MyS3BotoStorage(S3BotoStorage):
@property
def bucket(self):
if self._filename.endswith('.jpg'):
return self._get_or_create_bucket('SomeBucketName')
else:
return self._get_or_create_bucket('SomeSaneDefaultBucket')
def _save(self, name, content):
# This part might need some work to normalize the name and all...
self._filename = name
return super(MyS3BotoStorage, self)._save(name, content)
这篇关于如何动态选择models.FileField的存储选项?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!