Как динамически выбрать вариант хранения для моделей.FileField?

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

Однако это не дает желаемых результатов. В моем шаблоне, когда я пытаюсь перейти к 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 является? Как я могу это исправить?

1 ответ

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

РЕДАКТИРОВАТЬ:

Чтобы немного расширить это, источник для S3BotoStorage.__init__ имеет 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)
Другие вопросы по тегам