You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 20:39:21