文件下载功能
相应内容除了返回网页的信息外,还可以实现文件的下载功能,Django提供三种下载文件的功能,分别是:HttpResponse,StreamingHttpResponse,FileResponse.
- HttpResponse:是所有响应过程的核心类,它的底层功能类是HttpResponseBase
- StreamingHttpResponse:是在HttpResponseBase的基础上进行继承和重写的,它实现流式响应输出(是使用python的迭代器将数据进行分段处理并输出)。适用于大型规模数据响应和文件传输响应
- FileResponse:是在StreamingHttpResponse的基础上继承重写的,它实现文件的流式响应输出,只适合用于文件传输和响应
class StreamingHttpResponse(HttpResponseBase): streaming = True def __init__(self, streaming_content=(), *args, **kwargs): super().__init__(*args, **kwargs) # `streaming_content` should be an iterable of bytestrings. # See the `streaming_content` property methods. self.streaming_content = streaming_content
- streaming_content:的数据格式可设为迭代器对象或字节流,代表数据或文件内容
- *args, **kwargs:设置HttpResponseBase的参数,即响应内容的数据格式,content_type和响应状态码status等参数。
若使用StreamingHttpResponswene实现文件下载,则文件以字节的方式读取,在StreamingHttpResponse实列化时传入文件的字节流,由于该类支持数据或文件内容的响应方式输出,因此还需设置响应内容的数据格式和文件下载格式。
class FileResponse(StreamingHttpResponse): """ A streaming HTTP response class optimized for files. """ block_size = 4096 def __init__(self, *args, as_attachment=False, filename='', **kwargs): self.as_attachment = as_attachment self.filename = filename super().__init__(*args, **kwargs)
- as_attachment:的数据类型为布尔类型,若为False,则不提供文件下载功能,文件将会在浏览器打开并读取,若浏览器无法打开文件,则将文件下载到本地计算机,但没有设置文件的后辍吗,若为True,则开启文件下载功能,将文件下载到本地计算机并设置文件后辍名。
- filename:设置下载文件的文件名,该参数和参数as_attachment的设置参数有关,若参数as_attachment为False,则参数filename不做任何作用,在as_attachment为True的情况下,若参数filename为空的情况下,则使用该文件原有的文件名作为下载文件的文件名,反之以filename的参数为文件名
- *args, **kwargs:用于设置HttpResponseBase的参数,即响应内容的数据格式,content_type和响应状态码status等参数
urlpatterns=[ path('file1',views.download1,name='download1'), path('file2',views.download2,name='download2'), path('file3',views.download3,name='download3') ]
def index(request): return render(request,'index-1.html') def download1(request): file_path='D:\cot.jpg' try: r=HttpResponse(open(file_path,'rb')) r['content_type']='application/octet-stream' r['Content-Disposition']='attachment;filename=cat.jpg' return r except Exception: raise Http404('错误') def download2(request): file_path='D:\coe.jpg' try: r = StreamingHttpResponse(open(file_path, 'rb')) r['content_type'] = 'application/octet-stream' r['Content-Disposition'] = 'attachment;filename=coe.jpg' return r except Exception: raise Http404('错误') def download3(request): file_path='D:\coa.jpg' try: f=open(file_path, 'rb') r = FileResponse(f,as_attachment=False,filename='dog.jpg') return r except Exception: raise Http404('错误')
- 视图函数download1使用HttpResponse实现文件下载,将文件以字节流的方式读取并传入响应类HttpResponse进行实列化,并对实列化对象r设置参数content_type和Content-Disposition,这样就可以实现下载
- 视图函数download2使用StreamingHttpResponse实现下载,使用方式和HttpResponse相同
- 视图函数download3使用FileResponse实现文件下载,该类的使用方式最为简单,将文件以字节流的方式读取并设置参数as_attachment和filename,然后将三者一并传入FileResponse进行实列化即可
三者之间的差异
- HttpResponse:实现文件下载会有很大的弊端,其工作原理的是文件读取并载入内存,然后输出到浏览器上实现下载功能,如果下载的文件过大,该方法就会占用很大的内存,对于文件下载,Django推荐使用StreamingHttpResponse,FileResponse,这两个方法将下载文件分批写入服务器的本地磁盘,而不在将文件载入服务器的内存。
- 从适合范围来说,StreamingHttpResponse的适用方式更为广泛,可支持大规模数据或文件输出,而FileResponse只支持文件输出
- 从使用方式来说,由于StreamingHttpResponse支持数据和文件输出,因此在使用时候需要设置响应输出类型和方式,而FileResponse只需要设置3个参数即可实现文件下载功能。
文件上传功能
import os def index(request): if request.method=='POST': #判断是否为POST请求 myFile=request.FILES.get('myfile',None) print(myFile) if not myFile: return HttpResponse('no file for index') f=open(os.path.join('D:\sword',myFile.name),'wb+') print(f) for chunk in myFile.chunks(): #分块写入文件 print(chunk) f.write(chunk) f.close() return HttpResponse('index over') else: return render(request,'index.html')#请求方法为GET时候,生成文件上传页面
<form action="" method="post" enctype="multipart/form-data"> {% csrf_token %} <input type="file" name="myfile" > <input type='submit' value="文件上传"> </form>
- 模板文件index.html使用form标签的文件控件file生成文件的上传功能,该控件将用户上传的文件以二进制读取,读取方式由form标签的属性enctype="multipart/form-data"设置
- 浏览器将用户上传的文件读取后,通过HTTP的post请求将二进制的文件 传到Django当Django收到post请求后,从请求对象属性FILES获取文件信息,然后在D盘的sword文件里创建文件,文件名从myFile.name获取,与用户上传的文件名字相同。
- 从文件信息对象myFile.chunks()读取文件内容,并写入D盘中,从而实现文件的上传功能。
如果将form标签属性enctype="multipart/form-data"去掉,当用户在浏览器操作文件上传的时候,Django无法从请求对象里面FILES获取文件信息,file变为请求参数的形式传递
上述的myFile包含文件的基本信息,比如文件名,大小和后辍名。
- myFile.name:获取上传文件的文件名,包含文件的后辍名
- myFile.size:获取文件上传的大小
- myFile.content_type:获取文件的类型,通过后续名判断文件的类型
从文件对象myFile获取文件内容,Django提供以下属性来获取文件信息
- myFile.read():从文件对象里读取整个文件的长传的数据,这个方法只适合小文件
- myFile.chunks:按流式响应方式读取文件,,在for循环中进行迭代,将文件分块写入服务器所的指定位置。
- myFile.multipe_chunks:判断文件对象的文件大小,返回布尔值,当文件大于2.5MB,返回True,否则返回Flase.
源文件
class UploadedFile(File): #文件上传的基本功能类,继承父类file,该类主要获取文件的文件名,大小和类型等基本信息 class TemporaryUploadedFile(UploadedFile): #将文件数据临时存放在服务器所指定的文件里,适用于大文件的上传 class InMemoryUploadedFile(UploadedFile): #将文件数据存在内存里,适用于小文件的上传 class SimpleUploadedFile(InMemoryUploadedFile): #将文件名,大小和类型生成字典
myFile.chunks,myFile.read读取文件内容时候,其实质分别是调用InMemoryUploadedFile, TemporaryUploadedFile来实现文件上传的,两者之间的区别在于保存上传文件之前,文件数据需要存放在某个位置,默认情况下,当大小小于2.5MB的时候Django会通过InMemoryUploadedFile把上传的文件全部内容读进内存,当上传文件大于2.5MB时候,Django会使用TemporaryUploadedFile把上传的文件写到临时文件中,从而节省内存的开销。
在这4个功能类的基础上,Django进一步完善了文件的上传功能,主要完善了文件的创建,读写,和关闭等功能,处理过程在uploadhandler.py该文件定义了7个类和一个函数。7个类可以划分为两个类型,分别是异常处理和程序处理,,异常处理是处理文件上传过程中出现的异常情况,如上传中断,网络延迟,程序处理是实现文件上传过程,其中TemporaryFileUploadHandler是调用TemporaryUploadedFile来实现上传。MemoryFileUploadHandler是调用InMemoryUploadedFile,无论哪个类,Django都为文件上传机制配了4个属性
- FILE_UPLOAD_MAX_MEMORY_SIZE:判断文件的大小,默认2.5MB
- FILE_UPLOAD_PERMISSIONS:用于配置文件上传的权限
- FILE_UPLOAD_TEMP_DIR:用于配置文件数据的临时存放文件
- FILE_UPLOAD_HANDLERS:设置文件上传的处理过程。