django S3 - trim imagefield filename but not the url path
Asked Answered
P

3

13

this is a followup to my question here: ImageField / FileField Django form Currently unable to trim the path to filename

In my Django app, there is an imagefield uploaded to S3 After trim the imagefile path name, the image is not accessible because the url is trimmed. How can I trim the display but don't trim the path?

I manage to trim the display showing the filename like this

class CustomClearableFileInput(ClearableFileInput):

    def get_context(self, name, value, attrs):
        logging.debug("%s",name)
        logging.debug("%s",value)
        value.name = path.basename(value.name)
        context = super().get_context(name, value, attrs)       
        return context

    class CompanySettingEdit(forms.ModelForm):
       company_logo = forms.ImageField(widget=CustomClearableFileInput)

this is the output:

https://imgur.com/a/M42Mz <-- display correct
https://bucketname.s3.amazonaws.com/media/certiport_logo.png <-- invalid url

If I dont trim it:

class CustomClearableFileInput(ClearableFileInput):

    def get_context(self, name, value, attrs):
        logging.debug("%s",name)
        logging.debug("%s",value)
        # value.name = path.basename(value.name) <-- remove this
        context = super().get_context(name, value, attrs)       
        return context

    class CompanySettingEdit(forms.ModelForm):
       company_logo = forms.ImageField(widget=CustomClearableFileInput)

this is the output:

https://imgur.com/a/rGi8f <-- display incorrect
https://bucketname.s3.amazonaws.com/media/company_logo/15/certiport_logo.png <--valid url

my goal is to:

display: certiport_logo.png
url: https://bucketname.s3.amazonaws.com/media/company_logo/15/certiport_logo.png

How can I achieve this ?

Primateship answered 18/1, 2018 at 5:25 Comment(4)
I'm not sure if this would be optimal - what if someone has uploaded two images to /company_logo/15/certiport_logo.png and /company_logo/14/certiport_logo.png What would /media/certiport_logo.png point to then?Salamis
well... its possible to randomize it. its not an issue. the problem is the url is not correct. i want it to use the actual url to point to the trimmed name.Primateship
Have you tried adding a property to your CompanySetting model which returns a trimmed url and let the company_logo field be the actual full url?Salamis
what for ? the problem is more the link (url) is not correct. currently you can get the correct url with .url. the question is display and link it to the right url. is not possible ?Primateship
P
1

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 #}
    </a>
    {% 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" %} />
Proglottis answered 1/5, 2018 at 23:52 Comment(0)
T
0

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'
Thin answered 15/2, 2020 at 10:47 Comment(0)
K
-1

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'}
obj.save()

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)
Krasnodar answered 9/4, 2018 at 15:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.