Поле файла формы Django исчезает при ошибке формы

#django #file-upload #django-forms #validation

#django #загрузка файла #django-forms #проверка

Вопрос:

Вот проблема, у меня есть форма Django, содержащая поле файла, а именно:

 photo = forms.FileField(help_text="Please attach a photo", required=False)
  

Если форма проверяется, поле файла ограничено и сохранено правильно. Проблема заключается в том, что пользователь заполняет всю форму, и она не проверяется: путь к выбранному файлу исчезает.

Итак, если пользователь не осознает этого, он / она исправляет ошибки в других полях и отправляет снова — на этот раз без фотографии.

На всякий случай форма создается в представлении следующим образом:

 ProfileForm(request.POST or None, request.FILES or None)
  

и HTML-код:

 <div id="uniform-id_photo" class="uploader">
  <input id="id_photo" class="clearablefileinput" type="file" name="photo" size="19" style="opacity: 0;">
  <span class="filename" style="-moz-user-select: none;">No file selected</span>
  <span class="action" style="-moz-user-select: none;">Choose File</span>
</div>
  

У кого-нибудь раньше была такая же проблема? Есть мысли о решении? 🙂

Спасибо!

Комментарии:

1. Если вы посмотрите на администратора django, всякий раз, когда вы отправляете неправильную форму, он сбрасывает пути к файлам. Я думаю, что нет никакого способа сделать это, но почему бы не выделить поле файла в вашем html?

2. Да, это был бы, вероятно, лучший простой способ привлечь внимание пользователя. Спасибо!

Ответ №1:

К сожалению, это проблема (на самом деле функция безопасности), налагаемая браузерами, и как таковая неразрешима. Браузеры не позволят вам указать начальное значение для входных данных файла, и вы ничего не сможете сделать, чтобы обойти это.

Причина в том, что если бы веб-сайт мог это сделать, он открыл бы вектор, который позволил бы любому веб-сайту украсть любой файл на вашем компьютере, угадав пути к файлам — у них мог просто быть скрипт, работающий в фоновом режиме, который пытался отправить интересные файлы обратно на сервер.

Единственным обходным путем является фактическое сохранение загруженного файла на сервере независимо от того, проверяется ли форма, а затем, когда вы возвращаете форму и ошибки пользователю, укажите, что вы получили файл и что они должны заполнить это поле только для его замены.

Комментарии:

1. Другим обходным путем является выполнение AJAX-запроса для проверки формы.

Ответ №2:

Я пишу какое-то решение:

 class CustomClearableFileInput(ClearableFileInput):

def render(self, name, value, attrs=None):
    if len(<YourModel>.objects.filter(id=self.form_instance_id))>0:
        file = <YourModel>.objects.get(id=self.form_instance_id).<yourField>
    else:
        file = ''
    substitutions = {
        'initial_text': self.initial_text,
        'input_text': self.input_text,
        'clear_template': '',
        'clear_checkbox_label': self.clear_checkbox_label,
    }
    template = '%(input)s'
    substitutions['input'] = super(ClearableFileInput, self).render(name, value, attrs)
    self.template_with_initial = ('<p class="file-upload">%s</p>'
                        % self.template_with_initial)
    self.template_with_clear = ('<span class="clearable-file-input">%s</span>'
                       % self.template_with_clear)

    if value and hasattr(value, "url"):
        template = self.template_with_initial
        substitutions['initial'] = format_html(self.url_markup_template,
                                               value.url,
                                               force_text(value))
        if not self.is_required:
            checkbox_name = self.clear_checkbox_name(name)
            checkbox_id = self.clear_checkbox_id(checkbox_name)
            substitutions['clear_checkbox_name'] = conditional_escape(checkbox_name)
            substitutions['clear_checkbox_id'] = conditional_escape(checkbox_id)
            substitutions['clear'] = CheckboxInput().render(checkbox_name, False, attrs={'id': checkbox_id})
            substitutions['clear_template'] = self.template_with_clear % substitutions
            url = '' if file == '' else file.url
    else:
        template = self.template_with_initial

        substitutions['initial'] = format_html(self.url_markup_template,
                                               url,
                                               force_text(file))
        if not self.is_required:
            checkbox_name = self.clear_checkbox_name(name)
            checkbox_id = self.clear_checkbox_id(checkbox_name)
            substitutions['clear_checkbox_name'] = conditional_escape(checkbox_name)
            substitutions['clear_checkbox_id'] = conditional_escape(checkbox_id)
            if fav == '':
                substitutions['clear'] = CheckboxInput().render(checkbox_name, False, attrs={'id': checkbox_id, 'disabled': 'disabled'})
            else:
                substitutions['clear'] = CheckboxInput().render(checkbox_name, False, attrs={'id': checkbox_id})
            substitutions['clear_template'] = self.template_with_clear % substitutions



    return mark_safe(template % substitutions)
  

И затем в вашей форме вы должны написать:

 class <YourModel>Form(ModelForm):
    class Meta:
        model = <YourModel>
        fields = '__all__'
        widgets= {'<YourField>': CustomClearableFileInput}

    def __init__(self, *args, **kwargs):
        super(OperatorSettingsForm, self).__init__(*args, **kwargs)
        self.fields['<YourField>'].widget.form_instance_id = self.instance.id
  

Это работает для меня. Я думаю, у вас тоже не будет проблем 🙂