form = AddItemForm(request.POST, request.FILES)
if form.is_valid()
do_stuff
return render_to_response(blah.html, {'form':form})
现在,form将包含错误信息以及字段的原始值,但它不会保留选定的文件 如果表单验证失败,如何保留所选文件?
答案 0 :(得分:10)
您想要做的是,出于安全原因,浏览器不允许文件输入框在页面加载时具有预先选择的值。即使它只是保留同一页面的前一个实例的值,也是如此。 Django无法改变这一点。
如果您想避免要求用户重新选择并重新上传文件,即使验证失败,您也需要保存上传的文件,然后用一些内容替换文件输入字段以表明您已经拥有数据。如果用户想要放入不同的文件,您可能还需要一个运行某些JavaScript的按钮来重新启用文件字段。我不认为Django会为此提供任何机器,因此您必须自己编写代码。
答案 1 :(得分:10)
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,
}
答案 2 :(得分:3)
好的,所以我首先投票并实现Narendra的解决方案,然后才意识到它无法正常工作,因为javascript无法设置输入类型=“文件”值。看到: 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>
答案 3 :(得分:2)
如果您正在使用modelForm并且您成功保存了具有fileField的该模型的新实例,Django将仅将文件自行保存到磁盘。
在您的情况下,您需要做的是从request.FILES字典中获取文件,并将其自行保存到磁盘。看起来应该是这样的。
input_file = request.FILES['fileformfieldname']
new_file = open('/path/to/file.xxx')
new_file.write(input_file.read())
现在您已将文件保存到磁盘,您只需记住该文件的路径,以便在用户重新提交失败的表单时再次打开它。
答案 4 :(得分:1)
有点棘手,但这是逻辑。
首次加载时,隐藏字段为空,因此没有任何反应 在选择文件时,它会在隐藏字段中保存路径+名称 在第二次加载时,隐藏字段不为空,因此它将设置文件路径
这样,所有脏工作都在浏览器中进行,除非您有有效的表单,否则您不必将文件保存在服务器上。