django S3 - обрезать имя файла изображения, но не URL-адрес

это продолжение моего вопроса здесь: Форма ImageField / FileField Django В настоящее время невозможно обрезать путь к имени файла

В моем приложении Django есть поле изображения, загруженное на S3. После обрезки пути к файлу изображения изображение недоступно, поскольку URL-адрес обрезан. Как я могу обрезать дисплей, но не обрезать путь?

Мне удается обрезать дисплей, показывающий имя файла, как это

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)

это вывод:

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

Если не обрезать:

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)

это вывод:

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

моя цель:

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

Как я могу этого добиться?


person Axil    schedule 18.01.2018    source источник
comment
Я не уверен, что это было бы оптимально — что, если бы кто-то загрузил два изображения в /company_logo/15/certiport_logo.png и /company_logo/14/certiport_logo.png На что тогда указывал бы /media/certiport_logo.png?   -  person Thomas Jiang    schedule 25.01.2018
comment
ну... его можно рандомизировать. это не проблема. проблема в том, что URL-адрес неверен. я хочу, чтобы он использовал фактический URL-адрес, чтобы указать на обрезанное имя.   -  person Axil    schedule 26.01.2018
comment
Вы пытались добавить свойство в свою модель CompanySetting, которое возвращает обрезанный URL-адрес и позволяет полю company_logo быть фактическим полным URL-адресом?   -  person Thomas Jiang    schedule 26.01.2018
comment
зачем? проблема в том, что ссылка (url) неверна. в настоящее время вы можете получить правильный URL-адрес с .url. вопрос отображается и связать его с правильным URL-адресом. это невозможно ?   -  person Axil    schedule 26.01.2018


Ответы (3)


Свойство url FileField/ImageField является динамическим: оно зависит от атрибута name точно так же, как str() во время его вызова. Вместо этого давайте напишем что-то помимо name и изменим шаблон, чтобы использовать его вместо этого:

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

И для шаблона (модифицированного и красиво напечатанного из источника django)

{% 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" %} />
person J. Merdich    schedule 01.05.2018

Если вы делаете это для администратора Django, это может вам помочь. Вы можете сохранить что угодно в имени поля изображения, так как это просто имя, которое используется для создания URL-адреса изображения.

Теперь, когда вы открываете администратор Django с полем изображения, форма будет вызывать класс Storage, определенный как DEFAULT_FILE_STORAGE в settings.py.

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

Теперь этот класс FileSystemStorage отвечает за создание URL-адреса изображения, которое будет открываться при нажатии на имя изображения в админке.

Теперь подойдите к вашей потребности. Поскольку вам нужно, чтобы имя изображения было просто certiport_logo.png, вы можете сохранить это имя в поле изображения и переопределить функцию url класса FileSystemStorage для создания URL-адреса. Вот пример

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)

Переопределите функцию url в соответствии с вашими потребностями для разных моделей Django, и вы сможете отображать только имя изображения даже с правильным URL-адресом изображения. Убедитесь, что новый путь к классу указан в settings.py.

DEFAULT_FILE_STORAGE = 'apps.commons.custom_storage.CustomStorage'
person Vineet Yadav    schedule 15.02.2020

В вашем случае я предлагаю JSONField вместо ImageField. Таким образом, вы можете иметь:

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

пример класса:

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)
person Goran    schedule 09.04.2018