django 文件下载
1. 最简单下载:将文件流放入HttpResponse对象即可,适合小文件的下载,但如果这个文件非常大,这种方式会占用大量. 如:
def file_download(request): # do something... with open('file_name.txt') as f: c = f.read() return HttpResponse(c)
2. 合理的文件下载
Django的HttpResponse对象允许将迭代器作为传入参数,将上面代码中的传入参数c换成一个迭代器 ,便可以将上述下载功能优化为对大小文件均适合.更加合理的文件下载功能,应该先写一个迭代器,用于处理文件, 然后将这个迭代器作为参数传递给StreaminghttpResponse对象,如:
from django.http import StreamingHttpResponse def big_file_download(request): # do something... def file_iterator(file_name, chunk_size=512): with open(file_name) as f: while True: c = f.read(chunk_size) if c: yield c else: break the_file_name = "file_name.txt" response = StreamingHttpResponse(file_iterator(the_file_name)) return response
3.最优文件下载
上述的代码,已经完成了将服务器上的文件,通过文件流传输到浏览器,但文件流通常会以乱码形式显示到浏览器中, 而非下载到硬盘上,因此,还要在做点优化,让文件流写入硬盘。优化很简单,给StreamingHttpResponse对象 的Content-Type和Content-Disposition字段赋下面的值即可,如:
response['Content-Type'] = 'application/octet-stream' response['Content-Disposition'] = 'attachment;filename="test.pdf"' 完整代码如下: from django.http import StreamingHttpResponse def big_file_download(request): # do something... def file_iterator(file_name, chunk_size=512): with open(file_name) as f: while True: c = f.read(chunk_size) if c: yield c else: break the_file_name = "big_file.pdf" response = StreamingHttpResponse(file_iterator(the_file_name)) response['Content-Type'] = 'application/octet-stream' response['Content-Disposition'] = 'attachment;filename="{0}"'.format(the_file_name) return response
4.文件名包含中文下载时文件名不对,原因是: url编码解码 ,解决方法如下
from django.utils.http import urlquote response[‘Content-Disposition‘] = ‘attachment;filename="%s"‘ % (urlquote(title))
5. 遇到的问题:
下面可以下载成功:
def cmdb_export(request): """ 下载文件,发调用写好的 下载文件的 函数总是报错,直接写过来没问题. :param request: :return: """ if request.method=="GET": print("导出ip...........hosts") dir_create() remove_file("hosts") obj = ServerConfInfo.objects.filter(deleted=False) for i in obj: filename = file_creat(file_name='hosts', mode="a", content=i.ip_net) response = StreamingHttpResponse(file_iterator(filename)) response['Content-Type'] = 'application/octet-stream' response['Content-Disposition'] = 'attachment;filename="{0}"'.format(filename) return response else: pass
可是改成调用写好的下载函数就报错 didn't return an HttpResponse object. It returned None instead
def cmdb_export(request): """ 下载文件,发调用写好的 下载文件的 函数总是报错,直接写过来没问题. :param request: :return: """ if request.method=="GET": print("导出ip...........hosts") dir_create() remove_file("hosts") obj = ServerConfInfo.objects.filter(deleted=False) for i in obj: filename = file_creat(file_name='hosts', mode="a", content=i.ip_net) dj_downloadfile(request,filename) ##这里调用写好的下载函数。 # txt = file_iterator(filename) # response = StreamingHttpResponse(file_iterator(filename)) # response['Content-Type'] = 'application/octet-stream' # response['Content-Disposition'] = 'attachment;filename="{0}"'.format(filename) # return response else: pass
dj_downloadfile()函数如下:
def dj_downloadfile(request,filename): """ 网页下载数据,发现引用该函数会出现错误,但是把代码拷贝过去是正常的. :param request: :param filename: :return: """ response = StreamingHttpResponse(file_iterator(filename)) response['Content-Type'] = 'application/octet-stream' response['Content-Disposition'] = 'attachment;filename="{0}"'.format(filename) return response
一搭搭
二搭搭
三搭搭