-
一:前言:响应内容除了返回网页信息外,还可以实现文件下载功能,是网站常用的功能之一。Django提供三种方式实现文件下载功能,分别是HttpResponse,StreamingHttpResponse和FileResponse。
-
二:三种方式说明如下
-
HttpResponse:是所有响应过程的核心类,它的顶层功能是HttpResponseBase;
-
StreamingHttpResponse:在HttpResponseBase的基础上进行继承与重写,它实现流式响应输出,适用于大规模响应和文件传输响应;
-
FileResponse:在StreamingHttpResponse的基础上进行继承与重写,它实现文件流式响应输出,只适合文件传输响应。
-
查看源码,from django.http import response
- 2.1:StreamingHttpResponse
-
class StreamingHttpResponse(HttpResponseBase):
"""
A streaming HTTP response class with an iterator as content.
This should only be iterated once, when the response is streamed to the
client. However, it can be appended to or replaced with a new iterator
that wraps the original content (or yields entirely new content).
"""
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等参数。
-:2.2:FileResponse
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=False,filename不起作用,若as_attachment=True,参数filename为空,则使用文件原有名称作为下载名称,反之以filename作为下载名称;
- *args, **kwargs设置HttpResponseBase的参数,即响应内容的数据格式,content_type和响应状态码status等参数。
- 三:示例
#blog/urls.py
from django.urls import path,re_path,include
from blog import views
urlpatterns = [
re_path('^download$',views.download),
re_path('download/file1$',views.download1,name = "download1"),
re_path('download/file2$',views.download2,name = "download2"),
re_path('download/file3$',views.download3,name = "download3"),
]
#view.py
from django.http.response import HttpResponse,Http404,StreamingHttpResponse,FileResponse
from pathlib import Path
BASE_DIR = Path(__file__).resolve().parent.parent
tu_dir = os.path.join(BASE_DIR,"media")
def download(req):
return render(req,"dowm.html")
def download1(req):
# return HttpResponse("download1")
file_path = os.path.join(tu_dir,'pic1.jpg')
try:
r = HttpResponse(open(file_path,'rb'))
r["content_type"] = 'application/octet-stream'
r["content-Disposition"] = 'attachment;filename="1.jpg"'
return r
except Exception:
raise Http404("down error")
def download2(req):
# return HttpResponse("download2")
file_path = os.path.join(tu_dir, 'pic2.png')
try:
r = StreamingHttpResponse(open(file_path, 'rb'))
r["content_type"] = 'application/octet-stream'
r["content-Disposition"] = 'attachment;filename="2.jpg"'
return r
except Exception:
raise Http404("down error")
def download3(req):
# return HttpResponse("download3")
file_path = os.path.join(tu_dir, 'pic3.jpg')
try:
f = open(file_path, "rb")
r = FileResponse(f, as_attachment=True, filename="3.jpg")
return r
except Exception:
raise Http404("down error")
templates/down.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<a href="{% url 'download1' %}">HttpResponse-下载</a>
<br>
<a href="{% url 'download2' %}">StreamingHttpResponse-下载</a>
<br>
<a href="{% url 'download3' %}">FileResponse-下载</a>
</body>
</html>
-
四:HttpResponse、StreamingHttpResponse和FileResponse 这三者的差异:
- HttpResponse 实现文件下载存在很大弊端,其工作原理是将文件读取并载入内存,然后输出到浏览器上实现下载功能。如果文件较大,该方法就会占用很多内存。对于下载大文件,Django推荐使用StreamingHttpResponse 和FileResponse 方法,这两个方法将下载文件分批写入服务器的本地磁盘,减少对内存的消耗。
- StreamingHttpResponse 和FileResponse 的实现原理是相同的,两者都是将下载文件分批写入本地磁盘,实现文件的流式响应输出。
- 从适用范围来说,StreamingHttpResponse 的适用范围更为广泛,可支持大规模数据或文件输出,而FileResponse 只支持文件输出。
- 从使用方式来说,由于StreamingHttpResponse 支持数据或文件输出,因此在使用时需要设置响应输出类型和方式,而FileResponse只需设置3个参数即可实现文件下载功能。