Подтвердить что ты не робот

Как сделать форму Django сохранить файл после неудачной проверки

form = AddItemForm(request.POST, request.FILES)

if form.is_valid()

   do_stuff

return render_to_response(blah.html, {'form':form})

Теперь форма будет содержать информацию об ошибке вместе с исходными значениями полей, но не сохраняет выбранный файл Как сохранить выбранный файл, если форма не прошла проверку?

4b9b3361

Ответ 1

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

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

Ответ 2

Попробуйте django-file-resubmit

insallation

pip install django-file-resubmit

settings.py

INSTALLED_APPS = {
    ...
    'sorl.thumbnail',
    'file_resubmit',
    ...
}

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
    },
    "file_resubmit": {
        'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
        "LOCATION": project_path('data/cache/file_resubmit')
    },
}

Использование

from django.contrib import admin
from file_resubmit.admin import AdminResubmitMixin

class ModelAdmin(AdminResubmitMixin, ModelAdmin):
    pass

или

from django.forms import ModelForm
from file_resubmit.admin import AdminResubmitImageWidget, AdminResubmitFileWidget

class MyModelForm(forms.ModelForm)

    class Meta:
        model = MyModel
        widgets = {
            'picture': AdminResubmitImageWidget,
            'file': AdminResubmitFileWidget, 
        }

Ответ 3

Итак, я сначала поддержал и реализовал решение Narendra, прежде чем осознать, что он не может работать, поскольку javascript не может установить значения input type="file". Видеть: http://www.w3schools.com/jsref/prop_fileupload_value.asp

Но вот решение, которое работает:

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

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

models.py

class Book(models.Model):
    pdf = models.FileField("PDF", upload_to="books/")
    author_email = models.EmailField("Author Email")

class TempPDF(models.Model):
    pdf = models.FileField("PDF", upload_to="books/")

forms.py

from project_name.app_name.models import Book, TempPDF
from django.forms import ModelForm
from django.contrib.admin.widgets import AdminFileWidget

class BookForm(ModelForm):
    class Meta:
        model = Book
        exclude = ['pdf',]

class TempPDFForm(ModelForm):
    class Meta:
        model = TempPDF
        widgets = dict(pdf = AdminFileWidget) 
        # The AdminFileWidget will give a link to the saved file as well as give a prompt to change the file.
        # Note: be safe and don't let malicious users upload php/cgi scripts that your webserver may try running.

views.py

def new_book_form(request):
    if request.method == 'POST': 
        ## Always try saving file.  
        try: 
            temp_pdf_inst = TempPDF.objects.get(id=request.POST.has_key('temp_pdf_id'))
        except:  ## should really catch specific errors, but being quick
            temp_pdf_inst = None
        temp_pdf_form = TempPDFForm(request.POST, request.FILES, instance=temp_pdf_inst, prefix='temp_pdf')
        if temp_pdf_form.is_valid() and len(request.FILES) > 0:
            temp_pdf_inst = temp_pdf_form.save()
            temp_pdf_id = temp_pdf_inst.id
        book_form = BookForm(request.POST, prefix='book')

        if book_form.is_valid(): # All validation rules pass
            book = book_form.save(commit=False)
            book.pdf = temp_pdf_inst.pdf
            book.save()
            if temp_pdf_inst != None:
                temp_pdf_inst.delete()
            return HttpResponseRedirect('/thanks/') # Redirect after POST
    else:
        book_form = BookForm() # An unbound form
        temp_pdf_form = TempPDFForm()
        temp_pdf_id = None 
    return render_to_response('bookform_template.html',
                              dict(book_form = book_form,
                                   temp_pdf_form = temp_pdf_form,
                                   temp_pdf_id = temp_pdf_id)
                              )

bookform_template.html

<table>
  {{ book_form }}
  {{ temp_pdf_form }}
  <input type="hidden" name="temp_pdf_id" value="{{ temp_pdf_id }}">
</table>

Ответ 4

Django сохранит файл на диске самостоятельно, если вы используете modelForm, и вы успешно сохраните новый экземпляр этой модели с файловым полем.

В вашем случае вам нужно получить файл из словаря request.FILES и сохранить его на диске самостоятельно. Он должен выглядеть примерно так.

input_file = request.FILES['fileformfieldname']
new_file = open('/path/to/file.xxx')
new_file.write(input_file.read())

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

Ответ 5

Немного сложно, но вот логика.

  • Наряду с вашим HTML файлом введите другое скрытое поле.
  • Запишите некоторый JavaScript, чтобы сохранить выбранный путь к файлу + имя в этом скрытом поле.
  • Во время загрузки страницы ваш JavaScript должен проверить значение скрытого поля и установить его в поле "Файл", если оно есть.

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

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