Django项目中如何同时实现模板渲染与文件下载功能?
问题
在基于Django开发的Web应用中,我实现了Excel文件上传功能,可基于文件数据完成特定计算并导出更新后的文件。但我还希望同时在模板中展示特定信息。以下是我在views.py中尝试的代码:
context = {'mttr_count': mttr_count, 'mttr_avg': mttr_avg, 'data':sheet} response = HttpResponse(content_type='application/ms-excel') response['Content-Disposition'] = 'attachment; filename="mttr.xls"' rendered = render_to_string('mttr/mttr-output.html', context) response = HttpResponse(rendered) wb.save(response) return response
但该代码未达到预期效果。请问如何实现点击提交按钮后,既渲染携带上下文数据的mttr.html模板,又完成修改后文件的下载?
解决方案
HTTP协议一次请求只能返回一个响应,没法在同一个视图里同时返回页面渲染和文件下载,可通过以下两种方式实现需求:
方法1:先渲染结果页面,前端自动触发下载
拆分视图逻辑:
- 第一个视图处理文件上传、计算,把生成的Excel存到服务器临时目录,同时将计算结果存入会话或数据库。
- 重定向到结果展示视图,从会话/数据库取数据渲染
mttr.html。
示例代码:
import os from django.conf import settings from django.shortcuts import redirect, render def upload_and_calculate(request): if request.method == 'POST': # 此处省略文件上传、数据计算、生成wb对象的逻辑 mttr_count = ... mttr_avg = ... # 保存Excel到临时目录 temp_dir = os.path.join(settings.MEDIA_ROOT, 'temp') os.makedirs(temp_dir, exist_ok=True) temp_file_path = os.path.join(temp_dir, 'mttr.xls') wb.save(temp_file_path) # 计算结果存入会话 request.session['mttr_count'] = mttr_count request.session['mttr_avg'] = mttr_avg request.session['temp_file'] = 'mttr.xls' return redirect('show_mttr_result') return render(request, 'mttr/upload.html') def show_mttr_result(request): context = { 'mttr_count': request.session.get('mttr_count'), 'mttr_avg': request.session.get('mttr_avg') } return render(request, 'mttr/mttr.html', context)模板添加自动下载脚本:
在mttr.html底部加入JS,页面加载后自动发起下载请求:<script> window.addEventListener('load', function() { window.location.href = "{% url 'download_mttr' %}"; }); </script>新增下载视图:
def download_mttr(request): temp_file = request.session.get('temp_file') temp_file_path = os.path.join(settings.MEDIA_ROOT, 'temp', temp_file) if os.path.exists(temp_file_path): with open(temp_file_path, 'rb') as f: response = HttpResponse(f.read(), content_type='application/ms-excel') response['Content-Disposition'] = f'attachment; filename="{temp_file}"' # 下载后删除临时文件,清理会话 os.remove(temp_file_path) del request.session['temp_file'] return response return HttpResponse("文件不存在", status=404)
方法2:结果页面添加手动下载按钮
如果不需要自动下载,可在结果页面展示数据的同时,提供下载按钮供用户手动触发:
视图逻辑调整:
def upload_and_show(request): if request.method == 'POST': # 省略上传、计算、保存Excel到临时目录的逻辑 mttr_count = ... mttr_avg = ... temp_file_name = 'mttr.xls' context = { 'mttr_count': mttr_count, 'mttr_avg': mttr_avg, 'download_url': reverse('download_mttr', kwargs={'file_name': temp_file_name}) } return render(request, 'mttr/mttr.html', context) return render(request, 'mttr/upload.html')模板添加下载按钮:
<a href="{{ download_url }}" class="btn">下载更新后的Excel文件</a>下载视图适配参数:
def download_mttr(request, file_name): temp_file_path = os.path.join(settings.MEDIA_ROOT, 'temp', file_name) if os.path.exists(temp_file_path): with open(temp_file_path, 'rb') as f: response = HttpResponse(f.read(), content_type='application/ms-excel') response['Content-Disposition'] = f'attachment; filename="{file_name}"' os.remove(temp_file_path) return response return HttpResponse("文件不存在", status=404)
内容的提问来源于stack exchange,提问作者wizard
相关产品推荐
相关产品推荐

