这种方式简单粗暴,适合小文件的下载,但如果这个文件非常大,这种方式会占用大量的内存,甚至导致服务器崩溃

更合理的文件下载功能

Django的HttpResponse对象允许将迭代器作为传入参数,将上面代码中的传入参数c换成一个迭代器,便可以将上述下载功能优化为对大小文件均适合;而Django更进一步,推荐使用StreamingHttpResponse对象取代HttpResponse对象,StreamingHttpResponse对象用于将文件流发送给浏览器,与HttpResponse对象非常相似,对于文件下载功能,使用StreamingHttpResponse对象更合理。

因此,更加合理的文件下载功能,应该先写一个迭代器,用于处理文件,然后将这个迭代器作为参数传递给StreaminghttpResponse对象,如:

fromdjango.httpimportStreamingHttpResponse

defbig_file_download(request):
#dosomething...

deffile_iterator(file_name,chunk_size=512):
withopen(file_name)asf:
whileTrue:
c=f.read(chunk_size)
ifc:
yieldc
else:
break

the_file_name="file_name.txt"
response=StreamingHttpResponse(file_iterator(the_file_name))

returnresponse

文件下载功能再次优化

上述的代码,已经完成了将服务器上的文件,通过文件流传输到浏览器,但文件流通常会以乱码形式显示到浏览器中,而非下载到硬盘上,因此,还要在做点优化,让文件流写入硬盘。优化很简单,给StreamingHttpResponse对象的Content-Type和Content-Disposition字段赋下面的值即可,如:

response['Content-Type']='application/octet-stream'
response['Content-Disposition']='attachment;filename="test.pdf"'

完整代码如下:

fromdjango.httpimportStreamingHttpResponse
defbig_file_download(request):
#dosomething...
deffile_iterator(file_name,chunk_size=512):
withopen(file_name)asf:
whileTrue:
c=f.read(chunk_size)
ifc:
yieldc
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)
returnresponse

具体导出文件格式

导出Excel表格

1.首先是直接导出Excel表格

首先获取要导出的数据、以列表方式保存。

然后将数据写入到Excel,以流的方式返回到页面下载。

importxlwt
importio
importjson
fromdjango.httpimportHttpResponse
defset_style(name,height,bold=False):
style=xlwt.XFStyle()#初始化样式
font=xlwt.Font()#为样式创建字体
font.name=name#'TimesNewRoman'
font.bold=bold
font.color_index=000
font.height=height
style.font=font
#设置单元格边框
#borders=xlwt.Borders()
#borders.left=6
#borders.right=6
#borders.top=6
#borders.bottom=6
#style.borders=borders

#设置单元格背景颜色
#pattern=xlwt.Pattern()
#设置其模式为实型
#pattern.pattern=pattern.SOLID_PATTERN
#设置单元格背景颜色
#pattern.pattern_fore_colour=0x00
#style.pattern=pattern

returnstyle

defwrite_excel(data,name,header):
#打开一个Excel工作簿
file=xlwt.Workbook()
#新建一个sheet,如果对一个单元格重复操作,会引发异常,所以加上参数cell_overwrite_ok=True
table=file.add_sheet(name,cell_overwrite_ok=True)
ifdataisNone:
returnfile
#写标题栏
row0=[u'业务',u'状态',u'北京',u'上海',u'广州',u'深圳',u'状态小计']
foriinrange(0,len(row0)):
table.write_merge(0,0,i,i,row0[i],set_style('TimesNewRoman',220,True))
table.write_merge(0,2,7,9,"单元格合并",set_style('TimesNewRoman',220,True))
"""
table.write_merge(x,x+m,y,w+n,string,sytle)
x表示行,y表示列,m表示跨行个数,n表示跨列个数,string表示要写入的单元格内容,style表示单元格样式。其中,x,y,w,h,都是以0开始计算的。
"""
l=0
n=len(header)
#写入数据
forlineindata:
foriinrange(n):
table.write(l,i,line[header[i]])
l+=1
#直接保存文件
#file.save("D:/excel_name.xls")
#写入IO
res=get_excel_stream(file)
#设置HttpResponse的类型
response=HttpResponse(content_type='application/vnd.ms-excel')
fromurllibimportparse
response['Content-Disposition']='attachment;filename='+parse.quote("excel_name")+'.xls'
#将文件流写入到response返回
response.write(res)
returnresponse

defget_excel_stream(file):
#StringIO操作的只能是str,如果要操作二进制数据,就需要使用BytesIO。
excel_stream=io.BytesIO()
#这点很重要,传给save函数的不是保存文件名,而是一个BytesIO流(在内存中读写)
file.save(excel_stream)
#getvalue方法用于获得写入后的byte将结果返回给re
res=excel_stream.getvalue()
excel_stream.close()
returnres

2.导出json文件

导出json文件不像Excel那么麻烦,只需要拼接json格式数据即可,直接导出到本地还是很简单,但是导出到网页,怎么像导出excel一样不保存到本地,直接将流返回?

defwrite_json(data):
try:
json_stream=get_json_stream(data)
response=HttpResponse(content_type='application/json')
fromurllibimportparse
response['Content-Disposition']='attachment;filename='+parse.quote("test")+'.json'
response.write(json_stream)
returnresponse
exceptExceptionase:
print(e)


defget_json_stream(data):
#开始这里我用ByteIO流总是出错,但是后来参考廖雪峰网站用StringIO就没问题
file=io.StringIO()
data=json.dumps(data)
file.write(data)
res=file.getvalue()
file.close()
returnres

3.导出压缩包

由于导出两个文件无法同时都返回,所以考虑将这两个文件放入包中,然后将包以流的方式返回。

思考?此时导出的是zip包中,我怎么将这两个文件流写入zip中,好像有点不太合理。后来在老大指导下先将要打包的文件保存到本地,打包到zip后,将本地的文件删除,随后将该zip文件流读取,写入到response,返回zip文件流。

defwrite_zip(e_data,j_data,export_name):
try:
#保存到本地文件
#返回文件名,注意此时保存的方法和前面导出保存的json、excel文件区别
j_name=write_json(j_data,export_name[1])
e_name=write_excel(e_data,export_name[1])
#本地文件写入zip,重命名,然后删除本地临时文件
z_name='export.zip'
z_file=zipfile.ZipFile(z_name,'w')
z_file.write(j_name)
z_file.write(e_name)
os.remove(j_name)
os.remove(e_name)
z_file.close()
#再次读取zip文件,将文件流返回,但是此时打开方式要以二进制方式打开
z_file=open(z_name,'rb')
data=z_file.read()
z_file.close()
os.remove(z_file.name)
response=HttpResponse(data,content_type='application/zip')
fromurllibimportparse
response['Content-Disposition']='attachment;filename='+parse.quote(z_name)
returnresponse
exceptExceptionase:
logging.error(e)
print(e)

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。

热门推荐

1 毛坯房验收经验和常识 看了之后再验房心里有底
2 二手房收房如何交接 二手房收房注意问题
3 专业验收毛坯房的价格 商品房验收合格的标准
4 精装房怎么验收 精装房请验房师有用吗
5 一般要到哪里找验房师 验房师有哪些作用呢
6 请人验房一般是多少钱 验房师费用是多少
7 怎样测量房子面积 建筑面积和使用面积怎么算
8 收房需要注意什么 仔细检查不松懈
9 收房时三书一证一表是什么 主要作用介绍
10 交房时交房税费有哪些 本文为你一一讲解
11 验房都需要验什么 要做哪些准备呢
12 毛坯房验房师有必要请吗 毛坯房装修完如何验收
13 地下室防水工程质量验收规范详解
14 水性涂料、油性涂料区别介绍
15 零基础布艺DIY工坊 教你做超萌猫头鹰钥匙包
16 三棵树漆怎么样?三棵树漆官方网站
17 家庭“装修套餐”中猫腻你知道吗?
18 小空间大浴望 卫浴间装修巧支招