首先说说我对文件导出下载的看法(思路):
1、浅短的认知
需求:把数据库中的数据导出到excel中,支持下载,
逻辑:1)把数据库中的数据存放到excel文件中,excel文件放到数据库中的目录中,
2)把文件所在路径拼接成url返还给前端页面,
3)前端页面请求此url路径,浏览器自动下载excel文件,
上述方法总结:
上面的方法确实能够做到数据的导出,但是有一下几个问题:
1、服务器中会保留所生成的文件,虽然也可以定时删除,但是对服务器进行了多次的IO操作,不是很推荐,但是如果需要保留用户导出了那些数据,就可以分析用户的行为,则此方法就很完美。
2、对于此方法还有个优点,可以避免重复的把数据进行导入到excel文件中,保存对应的查询条件,用来对应所生成的excel文件,第二次或者多次导出相同的数据就可以把excel文件直接给用户下载。
3、如果对于生成的文件没有作用,那么上述的方法就会导致服务器进行了多次IO操作,增加服务器压力。
2、深入一点的认知
在经过大佬的指点后,发现了另一种导出excel文件的方法,不用在服务器中生成excel文件,直接通过浏览器下载,把文件以流的方式给浏览器,就会自动下载。
话不多说看代码:
环境:Python 2.7、django 1.9
class TeseExeclView(View):
def get(self,request):
"""
导出excel表格
"""
list_obj = AccountChatInfo.objects.values('send_account','receive_account','content').order_by("-send_at")[:30000]
if list_obj:
# 创建工作薄
ws = Workbook(encoding='utf-8')
w = ws.add_sheet(u"数据报表第一页")
w.write(0, 0, u"发送帐号")
w.write(0, 1, u"接收帐号")
w.write(0, 2, u"内容")
# 写入数据
excel_row = 1
for obj in list_obj:
send = obj['send_account']
receive = obj['receive_account']
data_content = obj['content']
w.write(excel_row, 0, send)
w.write(excel_row, 1, receive)
w.write(excel_row, 2, data_content)
excel_row += 1
sio = StringIO.StringIO()
ws.save(sio)
sio.seek(0)
response = HttpResponse(sio.getvalue(), content_type='application/vnd.ms-excel')
response['Content-Disposition'] = 'attachment; filename=test.xls'
# 将文件流写入到response返回
response.write(sio.getvalue())
return response
else:
return JsonResponse('no data')
excel文件打包zip导出
这个目前没找到把excel文件流放到zip文件流中的方法,所以只能通过在服务器上生成文件来进行导出。
仅供参考-记得把文件路径修改成自己的
class TestExcelView(View):
'''excel导出'''
excel_title = [u'发送帐号', u'接收帐号', u'内容']
def excel_method(self, list_obj, file_dir_name):
'''生成每个excel文件的方法'''
# 创建工作薄
ws = Workbook(encoding='utf-8')
sheet_num = 1
w = ws.add_sheet(u"sheet" + str(sheet_num))
# excel表格第一行字段信息
for i, m in enumerate(self.excel_title):
w.write(0, i, m)
# 写入数据
excel_row = 1 # 记录行号
for obj in list_obj:
send = obj['send_account']
receive = obj['receive_account']
data_content = obj['content']
w.write(excel_row, 0, send)
w.write(excel_row, 1, receive)
w.write(excel_row, 2, data_content)
excel_row += 1
# excel最大行为65536,所以换第二个工作表写
if excel_row == 65536:
excel_row = 1
sheet_num += 1
w = ws.add_sheet(u"sheet" + str(sheet_num))
for i, m in enumerate(self.excel_title):
w.write(0, i, m)
# todo 你存要放文件的文件夹路径,记得修改成自己的
path = '../static/excel/'
# 路径不存在,就创建
if not os.path.exists(path):
os.makedirs(path)
file_name = file_dir_name + '.xls'
ws.save(path + file_name)
# 返回文件名
return file_name
def get(self,request):
try:
obj = AccountChatInfo.objects.values('send_account','receive_account','content').order_by("-send_at")
obj_count = obj.count()
print u'总数据量-', obj_count
excel_number = 300000 # 30万条数据一个excel文件
if obj_count:
excel_file_list = [] # excel文件列表
file_pageobj = []
# 计算总数据量能够导出多少个excel文件
if obj_count > excel_number:
file_num = obj_count // excel_number
remainder = obj_count % excel_number
if remainder != 0:
file_num = file_num + 1
for index in range(0, file_num):
if index == file_num - 1:
file_pageobj.append(list_obj[index * excel_number:])
else:
file_pageobj.append(list_obj[index * excel_number:(index + 1) * excel_number])
else:
file_pageobj = [list_obj]
file_dir_name = str(int(time.time()))
for index, i in enumerate(file_pageobj):
# 文件名取时间戳+下划线+编号
one_excel_name = file_dir_name + '_' + str(index)
# t1 = time.time()
try:
file_name = self.excel_method(i, one_excel_name)
except:
continue
# print time.time() - t1
excel_file_list.append(file_name)
# todo 你存要放文件的文件夹路径,记得修改成自己的
path = '../static/excel/'
with zipfile.ZipFile(path + '{}.zip'.format(file_dir_name), mode='w') as zf:
for m in excel_file_list:
if os.path.exists(path + m):
zf.write(path + m, os.path.basename(m))
# 删除保留的exccel文件
os.remove(path + m)
url = 'http://' + request.META['HTTP_HOST'] + '/static/excel/' + '{}.zip'.format(file_dir_name)
# print u'总时间--', time.time() - time1
return JsonResponse({'status': True, 'url': url})
else:
return JsonResponse({'status': False, 'url': '', 'msg': u'数据为空!'})
except Exception as e:
print e
return JsonResponse({'status': False, 'url': '', 'msg': u'导出失败!'})
如有不足恳请各位大佬指点–会更新,
参考–:https://blog.csdn.net/gezi_/article/details/77319688