如何动态选择models.FileField的存储选项? [英] How to dynamically select storage option for models.FileField?

查看:245
本文介绍了如何动态选择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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆