Python/Flask框架下如何实现前端用户下载处理后的Excel文件
解决方案
你的代码无法触发下载的核心原因有3个:
- 路由函数最终返回的是普通字符串
File has been uploaded,没有将文件响应对象返回给前端 process_xl函数仅在内存中加载了Excel文件,处理完成后没有将修改回写到磁盘文件- 未正确使用Flask内置的
send_file方法配置下载响应头,浏览器无法识别这是需要下载的附件
第一步:补全服务层处理逻辑
首先修正process_xl函数,补全业务处理逻辑后,必须调用工作簿的save方法将修改持久化到文件:
from flask import send_file import requests from openpyxl import load_workbook def weather(city): url = "https://community-open-weather-map.p.rapidapi.com/weather" querystring = {"q":f"{city}","lat":"0","lon":"0","callback":"test","id":"2172797","lang":"null","units":"imperial","mode":"HTML"} headers = { "X-RapidAPI-Key": "0a109dce92msh070cc32fb93c003p1e4e8djsnef8cf195fed1", "X-RapidAPI-Host": "community-open-weather-map.p.rapidapi.com" } response = requests.request("GET", url, headers=headers, params=querystring) return response.text def process_xl(filename): wb = load_workbook(filename=filename) sheet_1 = wb['Sheet1'] sheet_2 = wb['Sheet2'] city_1 = sheet_1['A1'].value # 补全你原本的city_2取值和后续数据处理逻辑,比如写入天气数据到对应单元格 # 示例:sheet_1['B1'] = weather(city_1) # 核心:必须保存修改,否则文件还是上传时的原始状态 wb.save(filename)
第二步:修正路由返回逻辑
路由中处理完文件后,直接返回send_file生成的响应对象,不要返回普通文本。
注意:你代码里的_file_是笔误,Python内置变量为双下划线包裹的__file__,写错会直接报变量未定义错误
import os from flask import Flask, render_template from flask_wtf import FlaskForm from wtforms import FileField, SubmitField from wtforms.validators import InputRequired from werkzeug.utils import secure_filename # 导入你自己写的处理函数 from your_service_module import process_xl app = Flask(__name__) app.config['SECRET_KEY'] = '替换为你自己的表单密钥' app.config['UPLOAD_FOLDER'] = '替换为你实际的上传目录路径' class UploadFileForm(FlaskForm): file = FileField('File', validators=[InputRequired()]) submit = SubmitField('Download File') @app.route('/', methods=['GET', 'POST']) def home_api(): form = UploadFileForm() if form.validate_on_submit(): file = form.file.data file_path = os.path.join( os.path.abspath(os.path.dirname(__file__)), app.config['UPLOAD_FOLDER'], secure_filename(file.filename) ) file.save(file_path) # 执行Excel内容处理 process_xl(file_path) # 核心:返回文件响应,配置为附件下载模式 return send_file( path_or_file=file_path, as_attachment=True, download_name=f"处理后_{secure_filename(file.filename)}", # xlsx格式对应的标准MIME类型 mimetype="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" ) return render_template('index.html', form=form)
可选优化:不落盘直接返回内存文件
如果不想在服务器上存储临时文件,可以将处理后的Excel直接写入内存流返回,性能更好也不需要手动清理临时文件:
from io import BytesIO def process_and_return_excel(uploaded_file): # 直接从上传的文件流加载工作簿,不需要存到磁盘 wb = load_workbook(uploaded_file) sheet_1 = wb['Sheet1'] # 执行你的数据处理逻辑 # ... # 将工作簿写入内存流 output = BytesIO() wb.save(output) # 将指针移回流开头,否则send_file会读到空内容 output.seek(0) return output
路由中对应修改为:
if form.validate_on_submit(): file = form.file.data excel_stream = process_and_return_excel(file) return send_file( excel_stream, as_attachment=True, download_name="处理后文件.xlsx", mimetype="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" )
注意事项
- 普通表单提交不需要写特殊JS逻辑,浏览器收到带
Content-Disposition: attachment响应头的文件流就会自动触发下载 - 如果前端用axios/fetch异步提交表单,需要额外处理blob类型响应,普通表单提交直接用上面的代码即可
- 生产环境记得加文件类型校验,避免用户上传非Excel文件导致解析报错
内容的提问来源于stack exchange,提问作者ojo
相关产品推荐
相关产品推荐

