Issues

Issue #136 wontfix

Different storage backend in testing mode and S3 in production mode

Ahmed EL Refaey
created an issue

In my case, I need to specify a bucket name in the model image field like:

profile_pic = models.ImageField(upload_to=UPLOAD_PATH, null=True, blank=True, storage=S3BotoStorage(bucket=PROFILE_IMGS_BUCKET))

I need to use the Django default storage backend in the testing mode, I tried to omit the option storage=S3BotoStorage(bucket=PROFILE_IMGS_BUCKET) and since my is imported only in the production mode:

if not DEBUG:
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto.S3BotoStorage'

It works!, but the problem is that image is uploaded to the default bucket "AWS_STORAGE_BUCKET_NAME" and I need to specify the bucket name here. The ugly solution is to modify the model code to be aware of the testing mode like this:

    #!python
if not TESTING:
    profile_pic = models.ImageField(upload_to=UPLOAD_PATH,   storage=S3BotoStorage(bucket=PROFILE_IMGS_BUCKET))
else:
    profile_pic = models.ImageField(upload_to=UPLOAD_PATH)

Do you have any other best practice for this case?

UPDATE

My Proposal is to define a storage backend factory like this:

settings.py

TESTING = sys.argv[1:2] == ['test']
PROFILE_IMGS_BUCKET = 'xyz-profile-images'
PRODUCT_IMGS_BUCKET = 'xyz-product-images'

storage_backend.py

from settings import TESTING, PROFILE_IMGS_BUCKET, PRODUCT_IMGS_BUCKET
from storages.backends.s3boto import S3BotoStorage

def get_profile_storage_backend():
    if TESTING:
        return None
    else:
        return S3BotoStorage(bucket=PROFILE_IMGS_BUCKET)

def get_product_storage_backend():
    if TESTING:
        return None
    else:
        return S3BotoStorage(bucket=PRODUCT_IMGS_BUCKET)

models.py

   #!python
   profile_pic = models.ImageField(storage=get_profile_storage_backend())
   image = models.ImageField(storage=get_product_storage_backend())

Comments (6)

  1. Ian Lewis

    If you would like to have a different backend in production and testing you can simply create two settings.py files for each environment and specify the settings module path using the --settings option to manage.py

    If your settings files were settings_testing.py and settings_production.py you would use them as follows:

    python manage.py runserver --settings=settings_testing

  2. Ahmed EL Refaey reporter

    Thanks Ian,

    I already have 2 different settings files for production and testings. The problem is the only way to specify the bucket name is by parametrizing the storage passed the ImageField object not in the settings.

  3. Rich Leland

    Ahmed EL Refaey thanks for submitting this ticket. I feel like this is a very specific use-case to your application and you've resolved it elegantly! In most user cases there are two buckets total - one for media and one for static. I'd say in 99% of cases people are simply using the upload_to argument to specify where items live within a bucket.

    In your case you want to change the buckets for individual file fields. While I understand your use, I do think it's something that is not common and should be implemented on the application side, not in django-storages.

    I'm going to mark this as wontfix, but know that I'll keep an eye on any other similar use cases and appreciate the discussion! It's really helpful for us to understand how everyone is using django-storages.

  4. Log in to comment