gpt4 book ai didi

python - 使用 MultipartEncoder 从一个 Flask 路径返回多个下载

转载 作者:太空宇宙 更新时间:2023-11-04 01:54:07 27 4
gpt4 key购买 nike

我想做什么
我正在构建一个简单的单路由 Flask 应用程序,该应用程序从单字段表单中获取值,创建多个 CSV 文件并在提交表单后自动提供文件。

现有的相关问题
我偶然发现了 Download multiple CSVs using Flask?包含 an answer 的问题这解释了如何准确地完成我想要做的事情:返回多个下载。

我的问题
我已经实现了 MultipartEncoder来自 requests_toolbelt如答案所示,但在提交表单时,它只下载一个没有扩展名的文件(以路线命名),而不是下载所有文件。

我试图诊断的事情
如果我在 notepad++ 中打开该文件,我可以看到所有 CSV 文件都包含在由它们的 Content-TypeContent-Disposition header 分隔的文件中。所以,数据都存在,但由于某种原因,文件没有单独下载。这让我相信我的表单配置错误或者我可能需要发布到不同的路由。

我做错了什么?如何完成从单个路径下载多个文件?

最小工作示例代码

应用.py

from flask import Flask, Response, render_template, request
from requests_toolbelt import MultipartEncoder
from wtforms import StringField, SubmitField
from wtforms.validators import DataRequired
from flask_bootstrap import Bootstrap
from flask_wtf import FlaskForm

app = Flask(__name__)
app.config['SECRET_KEY'] = 'n0T_a-R3a1_sEcR3t-KeY'
Bootstrap(app)

def build_files_for(term):
# Create CSV files based on term
# Return filenames
return ['filename1.csv', 'filename2.csv', 'filename3.csv']

@app.route('/', methods=['GET', 'POST'])
@app.route('/index', methods=['GET', 'POST'])
def index():
form = TermBuilderForm()
if form.validate_on_submit():
term_results = form.term.data
downloads = build_files_for(term_results)
me_dict = {}
for i, download in enumerate(downloads, 1):
me_dict['field' + str(i)] = (download, open(download, 'rb'), 'text/csv')
m = MultipartEncoder(me_dict)
return Response(m.to_string(), mimetype=m.content_type)
return render_template('index.html', form=form)

class TermBuilderForm(FlaskForm):
term = StringField('Term', validators=[DataRequired()], id='term')
submit = SubmitField('Create')

if __name__ == '__main__':
app.run(debug = True)

index.html

{% extends 'bootstrap/base.html' %}
{% import 'bootstrap/wtf.html' as wtf %}

{% block title %}
Term Builder
{% endblock %}

{% block scripts %}
{{ super() }}
{% endblock %}
{% block content %}
<div class="container" style="width:100%;padding-left:35px;">
{% block app_content %}
<h1>Term Builder</h1>
{% if form %}
<!--enctype="multipart/form-data"-->
<form id="termbuilder" action="{{ url_for('index') }}" method="post" style="width:30%">
<div style="display:none">{{ wtf.form_field(form.csrf_token) }}</div>
<div class="row">
{{ wtf.form_field(form.term) }}
</div>
<hr>
<p>{{ wtf.form_field(form.submit) }}</p>
</form>
{% endif %}
{% endblock %}
</div>
{% endblock %}

最佳答案

HTTP 协议(protocol)旨在为每个请求发送一个文件。

it just downloads a single file (named after the route) with no extension instead of downloading all the files.

这是浏览器的默认行为,你可以阅读它here

推荐的方式是压缩所有文件并在一次响应中发送。

获得您期望的行为的一种方法:

app.py返回要使用任何模板下载的文件列表(此处使用 index.html)并添加新路由 /files_download/<filename>按文件名下载文件

@app.route('/', methods=['GET', 'POST'])
@app.route('/index', methods=['GET', 'POST'])
def index():
form = TermBuilderForm()
if form.validate_on_submit():
term_results = form.term.data
downloads = build_files_for(term_results)
return render_template('index.html', form=form, files=downloads)
return render_template('index.html', form=form)

@app.route('/files_download/<filename>')
def files_download(filename):
return send_file(filename, mimetype='text/csv')

在模板中 return render_template('index.html', form=form, files=downloads) (此处 index.html )添加:

{% if files %}
<script>
var urls = []
{% for file in files %}
urls.push("{{ url_for('files_download', filename=file) }}")
{% endfor %}
urls.forEach(url => {
var iframe = document.createElement('iframe'); iframe.style.visibility = 'collapse';
iframe.style.visibility = 'collapse';
iframe.src = url;
document.body.append(iframe);
setTimeout(() => iframe.remove(), 2000);
});
</script>
{% endif %}

关于python - 使用 MultipartEncoder 从一个 Flask 路径返回多个下载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57297060/

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