[Fixed]-Django S3 – trim imagefield filename but not the url path


The url property of a FileField/ImageField is dynamic: it depends on the name attribute just as str() does at the time it is called. Instead, let’s write to something besides name and change the template to use it instead:

class CustomClearableFileInput(ClearableFileInput):
    template_name = 'path/to/clearable_file_input.html'
    # less confusing place than get_context...
    def format_value(self, value):
        if self.is_initial(value):
            value.basename = path.basename(value.name)
            return value

And for the template (modified and pretty printed from django source)

{% if widget.is_initial %}
    {{ widget.initial_text }}: 
    <a href="{{ widget.value.url }}">
        {{ widget.value.basename }} {# <== CHANGE #}
    {% if not widget.required %}
        <input type="checkbox" name="{{ widget.checkbox_name }}" id="{{ widget.checkbox_id }}" />
        <label for="{{ widget.checkbox_id }}">{{ widget.clear_checkbox_label }}</label>
    {% endif %}
    <br /> {{ widget.input_text }}:
{% endif %}
<input type="{{ widget.type }}" name="{{ widget.name }}"{% include "django/forms/widgets/attrs.html" %} />


If you are doing this for the purpose of Django admin then it might help you.
You can save anything in the name of the Image field as it just a name that is used to build the URL for the image.

Now when you open Django admin with an Image field in it, the form will call the Storage class defined as DEFAULT_FILE_STORAGE in settings.py.

DEFAULT_FILE_STORAGE = 'django.core.files.storage.FileSystemStorage'

Now this FileSystemStorage class is responsible to create the URL for the image which will open when you click on the Image name in the admin.

Now come to your need. As you require image name to be just certiport_logo.png, you can save this name to your image field and override FileSystemStorage class’ url function to create the URL. Here is the example

from django.core.files.storage import FileSystemStorage

class CustomStorage(FileSystemStorage):
    Override django default storage class to build urls
    def url(self, name):
        return "https://bucketname.s3.amazonaws.com/media/company_logo/15/{}".format(name)

Override the url function as per your need for different Django models and you will be able to show just image name even with the correct image URL.
Make sure to set new class path to settings.py

DEFAULT_FILE_STORAGE = 'apps.commons.custom_storage.CustomStorage'


In your case I suggest JSONField instead of ImageField. On that way you in your can have:

obj.my_image_field = {'display': 'certiport_logo.png', 'url': 'your_S3_url'}

class example:

class MyModel(models.Model):
    my_image_field = JSONField()

    def get_image_display(self):
        return self.my_image_field.get('display', None)

    def get_image_url(self):
        return self.my_image_field.get('url', None)

Leave a comment