目录
概述:
代码对比:
慢代码:
快代码:
参考:
概述:
在做python项目时,运用openpyxl 导出1万条数据要十几秒,导致接口超时报错。
代码对比:
慢代码:
? ? ? ? 以下代码导出1万条数据,接口耗时超过40秒。
@action(methods=["get"], detail=False, url_path='export-excel')
def export_excel(self, request):
type = request.query_params.get('type', None)
page_size = request.query_params.get('page_size', None)
if page_size is not None and int(page_size) > 10000:
return APIResponse(code=0, msg='page_size不能超过10000')
if not type or (str(type) != RecordTypeEnum.op and str(type) != RecordTypeEnum.login and str(
type) != RecordTypeEnum.invoke):
return APIResponse(code=0, msg='type参数错误')
queryset = self.filter_queryset(self.get_queryset())
page = self.paginate_queryset(queryset)
"""导出excel表格"""
# 创建工作薄
wb = Workbook()
wb.encoding = 'utf-8'
sheet1 = wb.active # 获取第一个工作表(sheet1)
sheet1.title = "sheet1" # 给工作表1设置标题
row_one = ['操作时间', '操作账号', '操作动作', '操作模块', '登录IP']
v_f = ['invoke_time', 'login_name', 'view', 'module_name', 'ip']
file_name = '操作日志.xlsx'
for i in range(1, len(row_one) + 1): # 从第一行开始写,因为Excel文件的行号是从1开始,列号也是从1开始
# 从row=1,column=1开始写,即将row_one的数据依次写入第一行
sheet1.cell(row=1, column=i).value = row_one[i - 1]
if page is not None:
serializer = self.get_serializer(page, many=True)
for d in serializer.data:
view = d.get("view")
if view in OP_DICT.keys():
d["view"] = OP_DICT.get(view)
max_row = sheet1.max_row + 1 # 获取到工作表的最大行数并加1
for x in range(1, len(v_f) + 1): # 将每一个对象的所有字段的信息写入一行内
f = v_f[x - 1]
val = d.get(f)
sheet1.cell(row=max_row, column=x).value = val
# 准备写入到IO中
output = BytesIO()
wb.save(output) # 将Excel文件内容保存到IO中
output.seek(0) # 重新定位到开始
# 设置HttpResponse的类型
response = HttpResponse(output.getvalue())
file_name = urlquote(file_name) # 使用urlquote()方法解决中文无法使用的问题
# response['content_type'] = 'application/vnd.ms-excel'
response['Content-Disposition'] = 'attachment; filename=' + file_name
# response.write(output.getvalue()) # 在设置HttpResponse的类型时,如果给了值,可以不写这句
return response
快代码:
? ?
write_only=True
?加上上面参数,耗时只有几秒,提升了十倍左右。
@action(methods=["get"], detail=False, url_path='export-excel')
def export_excel(self, request):
type = request.query_params.get('type', None)
page_size = request.query_params.get('page_size', None)
if page_size is not None and int(page_size) > 10000:
return APIResponse(code=0, msg='page_size不能超过10000')
if not type or (str(type) != RecordTypeEnum.op and str(type) != RecordTypeEnum.login and str(
type) != RecordTypeEnum.invoke):
return APIResponse(code=0, msg='type参数错误')
queryset = self.filter_queryset(self.get_queryset())
page = self.paginate_queryset(queryset)
"""导出excel表格"""
# 创建工作薄
wb = Workbook(write_only=True)
wb.encoding = 'utf-8'
sheet1 = wb.create_sheet()
row_one = ['操作时间', '操作账号', '操作动作', '操作模块', '登录IP']
v_f = ['invoke_time', 'login_name', 'view', 'module_name', 'ip']
file_name = '操作日志.xlsx'
sheet1.append(row_one)
if page is not None:
serializer = self.get_serializer(page, many=True)
for d in serializer.data:
view = d.get("view")
if view in OP_DICT.keys():
d["view"] = OP_DICT.get(view)
data_arr = []
for x in range(1, len(v_f) + 1): # 将每一个对象的所有字段的信息写入一行内
f = v_f[x - 1]
val = d.get(f)
data_arr.append(val)
sheet1.append(data_arr)
# 准备写入到IO中
output = BytesIO()
wb.save(output) # 将Excel文件内容保存到IO中
output.seek(0) # 重新定位到开始
# 设置HttpResponse的类型
response = HttpResponse(output.getvalue())
file_name = urlquote(file_name) # 使用urlquote()方法解决中文无法使用的问题
# response['content_type'] = 'application/vnd.ms-excel'
response['Content-Disposition'] = 'attachment; filename=' + file_name
# response.write(output.getvalue()) # 在设置HttpResponse的类型时,如果给了值,可以不写这句
return response
参考:
Optimised Modes — openpyxl 3.0.9 documentationhttps://openpyxl.readthedocs.io/en/stable/optimized.html#read-only-mode
|