2016-05-05 1 views
0

В зависимости от расширения файла, я хочу, чтобы файл был сохранен в определенном ковше AWS. Я попытался передать функцию опции storage, аналогично тому, как динамически определяется upload_to.Как динамически выбирать параметр хранения для моделей. FileField?

Однако это не дает желаемых результатов. В моем шаблоне, когда я пытаюсь href для document.docfile.url, ссылка не работает.

Проверка в оболочке, это происходит

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 есть? Как я могу это исправить?

ответ

0

Для того, что вы пытаетесь сделать, вам может быть полезно создать собственный бэкэнд для хранения и просто переопределить различные биты S3BotoStorage. В частности, если вы сделаете bucket_name недвижимость, вы сможете получить нужное вам поведение.

EDIT:

Чтобы расширить немного на это, source для S3BotoStorage.__init__ имеет bucket в качестве дополнительного аргумента. Дополнительно bucket, когда он используется в классе, является @param, что упрощает его отмену. Следующий код не проверен, но его должно быть достаточно, чтобы дать вам отправную точку

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) 
+0

Я не уверен, как это сработает. Мне нужно, чтобы ведро было определено расширением имени файла во время выполнения. Если я создам новый класс, который наследуется от S3BotoStorage, не потребуется ли мне в любом случае выбирать фиксированное ведро или запустить ту же проблему? – thatharmansingh

+0

Я сделал [это] (http://pastebin.com/raw/GQJ6ad72), но та же проблема существует, т.е. docfile.bucket назначается функция вместо строкового значения, а доступ к docfile.url позже дает ошибку, «Невозможно объединить str и функцию». – thatharmansingh

+0

Из того, что я вижу в исходном коде, нет, вам не придется выбирать его, когда вы его инициализируете. Если вы переопределите свойство bucket, вы получите доступ ко всем переменным экземпляра. Я думаю, что у вас будет доступ к имени файла в тот момент, который позволит вам правильно рассчитать, какой ковш вы хотите использовать. Любой способ взглянуть на исходный код S3BotoStorage. Вам не нужно переопределять слишком много методов. – Paul