Django中Excel文件导出无法自动下载问题排查
Excel导出问题:无法自动下载,但Network面板手动点击可触发
我点击导出按钮时,Excel文件无法自动下载,但在Chrome开发者工具的Network面板里点击export-status请求就能触发下载。已经设置Chrome允许自动下载,问题仍存在。请问这是浏览器新版本问题还是代码问题?
后端视图代码
@csrf_exempt def export_status(request): with connection.cursor() as cursor: cursor.execute(""" SELECT tev_incoming.id,tev_outgoing.dv_no AS dv_no, tev_incoming.code, tev_incoming.account_no, tev_incoming.id_no, tev_incoming.first_name, tev_incoming.middle_name, tev_incoming.last_name, tev_incoming.date_travel, tev_incoming.division, tev_incoming.section, tev_incoming.status_id, au.first_name AS incoming_by,rb.first_name AS reviewed_by, tev_incoming.original_amount, tev_incoming.final_amount, tev_incoming.incoming_in AS date_actual, tev_incoming.updated_at AS date_entry, tev_incoming.incoming_out AS date_reviewed_forwarded, tev_bridge.purpose AS purposes FROM tev_incoming INNER JOIN ( SELECT MAX(id) AS max_id FROM tev_incoming GROUP BY code ) AS latest_ids ON tev_incoming.id = latest_ids.max_id LEFT JOIN tev_bridge ON tev_incoming.id = tev_bridge.tev_incoming_id LEFT JOIN tev_outgoing ON tev_bridge.tev_outgoing_id = tev_outgoing.id LEFT JOIN auth_user AS au ON au.id = tev_incoming.user_id LEFT JOIN auth_user AS rb ON rb.id = tev_incoming.reviewed_by ORDER BY tev_incoming.id DESC; """) rows = cursor.fetchall() response = HttpResponse(content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') response['Content-Disposition'] = 'attachment; filename={date}-TRIS-REPORT.xlsx'.format( date=datetime.now().strftime('%Y-%m-%d'), ) workbook = Workbook() worksheet = workbook.active worksheet.title = 'REPORT' header_font = Font(name='Calibri', bold=True) centered_alignment = Alignment(horizontal='center') border_bottom = Border( bottom=Side(border_style='medium', color='FF000000'), ) wrapped_alignment = Alignment( vertical='top', wrap_text=True ) columns = [ 'DV NO', 'CODE', 'ACCOUNT NO', 'ID NO', 'FIRSTNAME', 'MIDDLENAME', 'LASTNAME', 'DATE TRAVEL', 'DIVISION', 'SECTION', 'STATUS ID', 'INCOMING BY', 'REVIEWED BY', 'ORIGINAL AMOUNT', 'FINAL_AMOUNT', 'DATE ACTUAL RECEIVED', 'DATE ENTRY', 'DATE REVIEWED FORWARDED', 'PURPOSE', ] row_num = 1 for col_num, column_title in enumerate(columns, 1): cell = worksheet.cell(row=row_num, column=col_num) cell.value = column_title cell.font = header_font column_letter = get_column_letter(col_num) column_dimensions = worksheet.column_dimensions[column_letter] for tris in rows: row_num += 1 row = [ tris[1], # dv_no tris[2], # code tris[3], # account_no tris[4], # id_no tris[5], # first_name tris[6], # middle_name tris[7], # last_name tris[8], # date_travel tris[9], # division tris[10], # section tris[11], # status_id tris[12], # incoming_by tris[13], # reviewed_by tris[14], # original_amount tris[15], # final_amount tris[16], tris[17], tris[18], # date_reviewed_forwarded tris[19], # purposes ] for col_num, cell_value in enumerate(row, 1): cell = worksheet.cell(row=row_num, column=col_num) cell.value = cell_value column_letter = get_column_letter(col_num) column_dimensions = worksheet.column_dimensions[column_letter] column_dimensions.width = 19 workbook.save(response) return response
前端AJAX代码
$.ajax({ type: 'POST', url: "{% url 'export-status' %}" }).done(function (data) { });
问题原因及解决方法
这是前端代码的问题,和浏览器版本无关。
原因分析
AJAX请求本身不会自动处理Content-Disposition: attachment响应头来触发下载。浏览器只有在处理直接发起的请求(比如点击链接、表单提交)时,才会识别这类响应头并弹出下载框。而在Network面板手动点击请求时,浏览器是模拟直接请求的行为,所以能触发下载。
解决方法
替换AJAX请求为以下任意一种方式:
- 使用表单提交
创建隐藏表单,点击导出按钮时提交:
<button id="exportBtn">导出Excel</button> <form id="exportForm" method="POST" action="{% url 'export-status' %}" style="display:none;"> {% csrf_token %} </form> <script> document.getElementById('exportBtn').addEventListener('click', function() { document.getElementById('exportForm').submit(); }); </script>
(注:后端的@csrf_exempt可以移除,保留CSRF防护更安全)
- 直接跳转链接
如果后端视图支持GET请求,可直接让按钮跳转:
<a href="{% url 'export-status' %}" class="btn">导出Excel</a>
或用JS触发跳转:
document.getElementById('exportBtn').addEventListener('click', function() { window.location.href = "{% url 'export-status' %}"; });
- 手动处理AJAX响应触发下载
若必须使用AJAX,在回调里手动创建Blob触发下载:
$.ajax({ type: 'POST', url: "{% url 'export-status' %}", xhrFields: { responseType: 'blob' // 指定响应为二进制类型 } }).done(function (data) { const url = window.URL.createObjectURL(data); const a = document.createElement('a'); a.href = url; a.download = `${new Date().toISOString().split('T')[0]}-TRIS-REPORT.xlsx`; document.body.appendChild(a); a.click(); window.URL.revokeObjectURL(url); document.body.removeChild(a); });
内容的提问来源于stack exchange,提问作者Henry
相关产品推荐
相关产品推荐

