[Solved]-Django-storages get the full S3 url

12👍

I know this question is already answered, but just in case someone is looking for what I needed when I stumbled across this question…

I found for large queries that pulling the url off of the model instance (report.file.url) was resulting in terrible performance in cases where I need to pull a lot of records, because Django does a database query per record when accessing model fields this way. Here is an example implementation of an alternate method where you can do the entire query up front and still get the url if you need it.

from django.core.files.storage import get_storage_class
from . import models

# instance of the current storage class
media_storage = get_storage_class()()

# grabs all of my reports at once and stores them in a list of dicts
# instead of separate Report instances
report_list = models.Report.objects.values()

# stick the urls into the my records
report_list = [
        {**report, "url": media_storage.url(report["file"])} 
        for report in report_list
]

5👍

The file should be located at :

cache = cache.objects.get(identifier=identifier)
cache_file = cache.cache_file
cache_file_url = cache.cache_file.url

Call this this to get the complete S3 URL but you should have set up django storages to get this.

0👍

Although we now have 2 good answers, it’s worth just exploring what is under the hood when it comes to the media_storage.url() call:

***N.B. Assume we have django-storages installed in settings.py and have the correct settings, for example:

# Defualt File Storage (Remote/Cloud Storage Service)
# https://docs.djangoproject.com/en/3.0/ref/settings/#default-file-storage
DJANGO_REMOTE_STORAGE_ON = bool(os.environ.get('DJANGO_REMOTE_STORAGE_ON'))

DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage' if DJANGO_REMOTE_STORAGE_ON else 'django.core.files.storage.FileSystemStorage'

if DEFAULT_FILE_STORAGE == 'storages.backends.s3boto3.S3Boto3Storage':
    AWS_STORAGE_BUCKET_NAME = os.environ.get('DJANGO_AWS_STORAGE_BUCKET_NAME')
    AWS_ACCESS_KEY_ID = os.environ.get('DJANGO_AWS_ACCESS_KEY_ID')
    AWS_SECRET_ACCESS_KEY = os.environ.get('DJANGO_AWS_SECRET_ACCESS_KEY')
    AWS_S3_REGION_NAME = os.environ.get('DJANGO_AWS_S3_REGION_NAME')
    AWS_S3_ENDPOINT_URL = os.environ.get('DJANGO_AWS_S3_ENDPOINT_URL')
    AWS_S3_OBJECT_PARAMETERS = { 'CacheControl': 'max-age=86400', }
    AWS_DEFAULT_ACL = 'public-read'
    AWS_BUCKET_ACL = 'public-read'
    AWS_IS_GZIPPED = True
    AWS_S3_USE_SSL = True
    AWS_QUERYSTRING_AUTH = False
from django.core.files.storage import get_storage_class

media_storage = get_storage_class()()

// Assume we know some sort of ID:
id = 1

// Retrieve the object instance from the ID (or other attribute field)
obj = Object.objects.get(id=id)

// Assuming we have some file field called "file":
boto_s3_url = media_storage.url(name=obj.file.name)

This ensures that regardless of our storage method, we’ll always retrieve the absolute URI location, e.g., "https://<AWS_S3_REGION_NAME>.<AWS_S3_ENDPOINT_URL>/<AWS_STORAGE_BUCKET_NAME>/<UPLOADS_TO>/<FILENAME>".

e.g., https://nyc3.digitaloceanspaces.com/asencis/datasets/records/files/CHANDRA.2.0.source.tsv

Leave a comment