当Django处理文件上载时,文件数据最终放入 request.FILES
#forms.py from django import forms class UploadFileForm(forms.Form): title = forms.CharField(max_length=50) file = forms.FileField()
处理此表单的视图将接收文件数据request.FILES,该文件数据 是包含 表单中每个FileField( ImageField或其他FileField子类)的键的字典。因此,上述表格中的数据可以作为request.FILES[‘file’]。
request.FILES请求方法是POST,并且发布的请求具有该属性,则应包含数据enctype=“multipart/form-data”。否则, request.FILES将是空的。
#views.py from django.http import HttpResponseRedirect from django.shortcuts import render from .forms import UploadFileForm # Imaginary function to handle an uploaded file. def upload_file(request): if request.method == 'POST': form = UploadFileForm(request.POST, request.FILES) if form.is_valid(): handle_uploaded_file(request.FILES['file']) return HttpResponseRedirect('/success/url/') else: form = UploadFileForm() return render(request, 'upload.html', {'form': form}) def handle_uploaded_file(f): with open('some/file/name.txt', 'wb+') as destination: for chunk in f.chunks(): destination.write(chunk)
使用模型处理上传的文件
如果您使用Model上 FileField将文件保存,则ModelForm 使此过程变得更加容易。调用时 form.save()该文件对象将被保存到由upload_to指定的位置对应的FileField参数:
from django.http import HttpResponseRedirect from django.shortcuts import render from .forms import ModelFormWithFileField def upload_file(request): if request.method == 'POST': form = ModelFormWithFileField(request.POST, request.FILES) if form.is_valid(): # file is saved form.save() return HttpResponseRedirect('/success/url/') else: form = ModelFormWithFileField() return render(request, 'upload.html', {'form': form})
如果要手动构建对象,只需将文件对象分配给request.FILES模型中的文件字段
from django.http import HttpResponseRedirect from django.shortcuts import render from .forms import UploadFileForm from .models import ModelWithFileField def upload_file(request): if request.method == 'POST': form = UploadFileForm(request.POST, request.FILES) if form.is_valid(): instance = ModelWithFileField(file_field=request.FILES['file']) instance.save() return HttpResponseRedirect('/success/url/') else: form = UploadFileForm() return render(request, 'upload.html', {'form': form})
上传多个文件
#forms.py from django import forms class FileFieldForm(forms.Form): file_field = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True}))
from django.views.generic.edit import FormView from .forms import FileFieldForm class FileFieldView(FormView): form_class = FileFieldForm template_name = 'upload.html' # Replace with your template. success_url = '...' # Replace with your URL or reverse(). def post(self, request, *args, **kwargs): form_class = self.get_form_class() form = self.get_form(form_class) files = request.FILES.getlist('file_field') if form.is_valid(): for f in files: ... # Do something with each file. return self.form_valid(form) else: return self.form_invalid(form)
上传处理程序
当用户上传文件时,Django将文件数据传递给上传处理程序 - 一个在上传时处理文件数据的小类。上传处理程序最初在FILE_UPLOAD_HANDLERS设置中定义,默认为:
["django.core.files.uploadhandler.MemoryFileUploadHandler", "django.core.files.uploadhandler.TemporaryFileUploadHandler"]
可以编写自定义处理程序来自定义Django处理文件的方式。例如,您可以使用自定义处理程序来强制执行用户级配额,动态压缩数据,渲染进度条,甚至直接将数据发送到另一个存储位置,而无需在本地存储。
存储上传数据的地方
在保存上传的文件之前,需要将数据存储在某处。
默认情况下,如果上传的文件小于2.5兆字节,Django会将上传的全部内容保存在内存中。这意味着保存文件只涉及从内存中读取和写入磁盘,因此非常快。
但是,如果上传的文件太大,Django会将上传的文件写入存储在系统临时目录中的临时文件中。在类似Unix的平台上,这意味着你可以期待Django生成一个类似的文件/tmp/tmpzfp6I6.upload。如果上传足够大,您可以观看此文件的大小增长,因为Django将数据流式传输到磁盘上。
动态修改上传处理程序
有时特定视图需要不同的上载行为。在这些情况下,您可以通过修改基于每个请求覆盖上载处理程序 request.upload_handlers。默认情况下,此列表将包含由其指定的上载处理程序FILE_UPLOAD_HANDLERS,但您可以像修改任何其他列表一样修改列表。
例如,假设您已经编写了一个ProgressBarUploadHandler提供有关上传进度的反馈到某种AJAX小部件。您可以将此处理程序添加到上传处理程序中,如下所示:
request.upload_handlers.insert(0, ProgressBarUploadHandler(request))
您可能希望list.insert()在这种情况下使用(而不是 append())因为进度条处理程序需要在任何其他处理程序之前运行。请记住,上传处理程序按顺序处理。
如果要完全替换上传处理程序,只需指定一个新列表:
request.upload_handlers = [ProgressBarUploadHandler(request)]
只能在访问之前修改上传处理程序,request.POST或者request.FILES- 在上载处理开始后更改上载处理程序没有意义。如果您request.upload_handlers在读取后尝试修改request.POST或request.FILES Django将抛出错误。
因此,应该尽可能早地在视图中修改上传处理程序。
此外,默认情况下启用该request.POST访问 CsrfViewMiddleware权限。这意味着您需要在视图上使用csrf_exempt()以允许您更改上载处理程序。然后,您需要使用 csrf_protect()实际处理请求的函数。请注意,这意味着处理程序可能会在CSRF检查完成之前开始接收文件上载。
from django.views.decorators.csrf import csrf_exempt, csrf_protect @csrf_exempt def upload_file_view(request): request.upload_handlers.insert(0, ProgressBarUploadHandler(request)) return _upload_file_view(request) @csrf_protect def _upload_file_view(request): ... # Process request