Django 文件下载

实现方式:a标签 +响应头信息(当然你可以选择form实现):
<div class="col-md-4"><a href="{% url 'download' %}" rel="external nofollow" >点我下载</a></div>
 

一、HttpResponse

django提供文件下载时,若是 文件较小,可先将要传送的内容全部生成在内存中,然后再一次性传入Response对象
def simple_file_download(request):
    # do something...
    content = open("simplefile", "rb").read()
    return HttpResponse(content)
若文件非常大,最简单的办法是使用静态文件服务器,比如Apache或者Nginx服务器来处理下载。不过,需要对用户的权限进行限定、或者不想向用户暴露文件的真实地址、或者这个大内容是临时生成的,这时就不能使用静态文件服务器了。
 
django文档中提到,可以向HttpResponse传递一个迭代器,流式的向客户端传递数据。
要自己写迭代器的话,可以用yield:
def read_file(filename, buf_size=8192):
    with open(filename, "rb") as f:
        while True:
            content = f.read(buf_size)
            if content:
                yield content
            else:
                break

def big_file_download(request):
    filename = "filename"
    response = HttpResponse(read_file(filename))
    response['content_type'] = 'application/octet-stream' # 设置头信息,告诉浏览器这是个文件
    response['Content-Disposition'] = 'attachment; filename=%s' % filename
    return response
项目中实战:
9f5be1e721f0483b9caf2c573f991df6.png
IE是根据Content-Disposition中filename这个段中文件名的后缀来识别这个文件类型的,所以,如果有很多种文件类型的时候,可以将Content-Type设置为二进制模式的:
response.setContentType("application/octet-stream")
 
Content-Disposition属性有两种类型:
  1. inline :将文件内容直接显示在页面
  2. attachment:弹出对话框让用户下载
 
python也提供一个文件包装器,将类文件对象包装成一个迭代器:
from django.core.servers.basehttp import FileWrapper
from django.http import HttpResponse
import os

def file_download(request,filename):
    wrapper = FileWrapper(open(filename, 'rb'))
    response = HttpResponse(wrapper, content_type='application/octet-stream')
    response['Content-Length'] = os.path.getsize(path)
    response['Content-Disposition'] = 'attachment; filename=%s' % filename
    return response
不过不管怎么样, 使用django来处理大文件下载都不是一个很好的注意,最好的办法是django做权限判断,然后让静态服务器处理下载
这需要使用sendfile的机制:"传统的Web服务器在处理文件下载的时候,总是先读入文件内容到应用程序内存,然后再把内存当中的内容发送给客户端浏览器。这种方式在应付当今大负载网站会消耗更多的服务器资源。sendfile是现代操作系统支持的一种高性能网络IO方式,操作系统内核的sendfile调用可以将文件内容直接推送到网卡的buffer当中,从而避免了Web服务器读写文件的开销,实现了“零拷贝”模式。 "
 
Apache服务器里需要mod_xsendfile模块来实现,而Nginx是通过称为X-Accel-Redirect的特性来实现。
nginx配置文件:
 
# Will serve /var/www/protected_files/myfile.tar.gz
# When passed URI /protected_files/myfile.tar.gz
location /protected_files {
    internal;
    root /var/www;
}
django中:
response['X-Accel-Redirect']='/protected_files/%s' % filename

这样当向django view函数发起request时,django负责对用户权限进行判断或者做些其它事情,然后向nginx转发url为/protected_files/filename的请求,nginx服务器负责文件/var/www/protected_files/filename的下载:

@login_required
def document_view(request, document_id):
    book = Book.objects.get(id=document_id)
    response = HttpResponse()
    name = book.myBook.name.split('/')[-1]
    response['Content_Type']='application/octet-stream'
    response["Content-Disposition"] = "attachment; filename={0}".format(name.encode('utf-8'))
    response['Content-Length'] = os.path.getsize(book.myBook.path)
    response['X-Accel-Redirect'] = "/protected/{0}".format(book.myBook.name)
    return response

二、StreamingHttpResponse

def download(request):
  file = open('crm/models.py','rb')
  response = StreamingHttpResponse(file)
  response['Content-Type'] = 'application/octet-stream'
  response['Content-Disposition'] = 'attachment;filename="models.py"'
  return response

三、FileResponse

from django.http import FileResponse

def download(request):
  file = open('crm/models.py','rb')
  response = FileResponse(file)
  response['Content-Type'] = 'application/octet-stream'
  response['Content-Disposition'] = 'attachment;filename="models.py"'
  return response

三种http响应对象在django官网都有介绍.入口:Request and response objects | Django documentation | Django

推荐使用FileResponse,从源码中可以看出FileResponse是StreamingHttpResponse的子类,内部使用迭代器进行数据流传输。

 

四、参考

https://www.jb51.net/article/137790.htm  详解django三种文件下载方式
https://www.cnblogs.com/qf123/p/10058721.html 下载文件时HttpServletResponse设置响应头的Content-Disposition属性

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值