gpt4 book ai didi

python - Flask 在流数据后加载新页面

转载 作者:行者123 更新时间:2023-12-05 02:27:29 24 4
gpt4 key购买 nike

我有一个简单的 Flask 应用程序,它可以上传 CSV 文件,进行一些更改,然后将结果作为 CSV 文件流式传输回用户的下载文件夹。

HTML 表单

<form action = {{uploader_page}} method = "POST" enctype = "multipart/form-data">
<label>CSV file</label><br>
<input type = "file" name = "input_file" required></input><br><br>
<!-- some other inputs -->
<div id = "submit_btn_container">
<input id="submit_btn" onclick = "this.form.submit(); this.disabled = true; this.value = 'Processing';" type = "submit"></input>
</div>
</form>

python

from flask import Flask, request, Response, redirect, flash, render_template
from io import BytesIO
import pandas as pd

@app.route('/uploader', methods = ['POST'])
def uploadFile():
uploaded_file = request.files['input_file']
data_df = pd.read_csv(BytesIO(uploaded_file.read()))
# do stuff

# stream the pandas df as a csv to the user download folder
return Response(data_df.to_csv(index = False),
mimetype = "text/csv",
headers = {"Content-Disposition": "attachment; filename=result.csv"})

效果很好,我在我的下载文件夹中看到了该文件。

但是,我想在完成后显示“下载完成”页面。

我该怎么做?通常我使用 return redirect("some_url") 来改变页面。

最佳答案

考虑使用 send_file()send_from_directory()用于发送文件。

从 1 个请求获得 2 个响应是不可能的,但是您可以借助一些 JS 将问题分成多个 block ,按照这个简单的图表(不是很精确的 UML,但仅此而已):

此图引用了以前的更简单版本的代码,后来在 OP 要求调用 flash() 后进行了更新

enter image description here

  1. POST 到 /uploader 通过 onsubmit 从表单调用的函数,这样除了保存文件你还可以在那里有一些逻辑,比如检查响应状态

  2. 处理文件(我通过upper() 模拟了你的处理过程)

  3. 如果服务器响应 201(“已创建”),那么您可以保存文件并打印“下载完成”(我使用了 window .document.body.innerHTML 因为它只有一个标签,我们可以替换之前所有的 DOM;它不应该被用来改变复杂的 HTML)

  4. 否则,如果服务器响应其他状态代码(如 500),POST 到 /something-went-wrong 以获取新的 - 可能已闪烁- 要呈现的 HTML。图中未显示 POST 步骤。

要测试错误页面,请在upload_file() 中处理一些语法错误,例如data_df = pd.read_csv(BytesIO(uploaded_file.aread ()))

something-went-wrong 响应中,我添加了一个 CSP header 以减轻可能的恶意攻击,因为我们不能足够信任用户。

代码如下:

主.py

from flask import (Flask,
request,
redirect,
render_template,
send_file,
url_for,
Response, jsonify, flash, make_response)
from flask_wtf.csrf import CSRFProtect

from io import BytesIO
import pandas as pd

app = Flask(__name__)
app.secret_key = "your_secret"

csrf = CSRFProtect(app)


@app.route('/')
def index():
return render_template("index.html")


@app.route("/uploader", methods=['POST'])
def upload_file():
try:
uploaded_file = request.files['input_file']
data_df = pd.read_csv(BytesIO(uploaded_file.read()))

# do stuff
data_df["foo"] = data_df["foo"].str.upper()

# Stream buffer:
io_buffer = BytesIO()
data_df.to_csv(io_buffer)
io_buffer.seek(0)

except Exception as ex:
print(ex) # and log if needed
# Here I return the exception string just as an example! Not good in real usage.
return jsonify({"message": str(ex)}), 500
else:
return send_file(io_buffer,
download_name="result.csv",
as_attachment=True), 201


@app.route("/something-went-wrong", methods=["POST"])
def something_went_wrong():
flash(request.get_json()["message"])
response = make_response(render_template("something-went-wrong.html"), 200)
response.headers['Content-Security-Policy'] = "default-src 'self'"
return response

带有 JS 处理程序的表单:

<form id="myForm" enctype="multipart/form-data" onsubmit="return submitHandler()">
<input type="hidden" name="csrfToken" value="{{ csrf_token() }}"/>
<label>CSV file</label><br>
<input type="file" id="inputFile" name="input_file" required/><br><br>
<!-- some other inputs -->
<div id="submitBtnContainer">
<input id="submitBtn" type="submit"/>
</div>
</form>

<script>
function submitHandler() {
const csrf_token = "{{ csrf_token() }}";

let formData = new FormData();
const file = document.getElementById('inputFile').files[0];
formData.append("input_file", file);

fetch("/uploader", {
method: "POST",
body: formData,
headers: {
"X-CSRFToken": csrf_token,
},
})
.then(response => {
if (response.status != 201) {
response.json().then(data => {
fetch("/something-went-wrong", {
method: "POST",
body: JSON.stringify({"message": data["message"]}),
headers: {
"Content-Type": "application/json",
"X-CSRFToken": csrf_token,
},
})
.then(response => response.text())
.then(text => {
window.document.body.innerHTML = text;
})
});
}
else {
return response.blob().then(blob => {
const file = new Blob([blob], { type: 'text/csv' });
const fileURL = URL.createObjectURL(file);
let fileLink = document.createElement('a');
fileLink.href = fileURL;
fileLink.download = "result.csv";
fileLink.click();
window.document.body.innerHTML = "<h1>Download Complete</h1>";
});
}
})
return false;
}
</script>

为了完整起见,我的虚拟 csv "file.csv":

<表类="s-表"><头><日>富 <正文>栏

关于python - Flask 在流数据后加载新页面,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73087264/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com