使用 Flask 发送多个 CSV?

Send with multiple CSVs using Flask?

我有一个应用程序可以接收一些信息,使用 pandas 执行一些计算,并将最终的 pandas 数据帧转换为 CSV,然后使用 Flask 应用程序下载。如何在一个视图中下载多个 CSV?我好像一次只能return一个回复。

示例片段:

def serve_csv(dataframe,filename):
    buffer = StringIO.StringIO()
    dataframe.to_csv(buffer, encoding='utf-8', index=False)
    buffer.seek(0)
    return send_file(buffer,
             attachment_filename=filename,
             mimetype='text/csv')

def make_calculation(arg1, arg2):
   '''Does some calculations.
   input: arg1 - string, arg2- string
   returns: a pandas data frame'''

@app.route('test_app', methods=['GET', 'POST'])
def test_app():
    form = Form1()
    if form.validate_on_submit():
    calculated_dataframe = make_calculation(str(form.input_1.data), str(form.input_2.data))
        return serve_csv(calculated_dataframe, 'Your_final_output.csv')
    return render_template('test_app.html', form=form)

所以让我们在上面的例子中说 make_calculation returned 两个 pandas 数据帧。我如何将它们都打印到 CSV 文件中?

你可以 return MIME Multipart response, a zip file, or a TAR ball (please note the linked RFC is somewhat out of date, but is easier to quickly get up to speed with because it's in HTML; the official one is here).

如果您选择执行 MIME 多部分响应,一个好的起点可能是查看 MultipartEncoder and MultipartDecoder in requests toolbelt; you may be able to use them directly, or at least subclass/compose using those to get your desired behavior. Zip files and TAR balls can be implemented using standard library modules。

另一种方法是设计您的 API,以便您 returning JSON,使用 header(或 XML 元素或 JSON 字段)以指示其他 CSV 可以通过另一个请求或类似请求获得。

这是 使用 Zip files 所需的所有代码。它将 return 一个包含所有文件的 zip 文件。

在我的程序中,我想要压缩的所有内容都在 output 文件夹中,所以我只使用 os.walk 并将其放入带有 write 的 zip 文件中。在 return 之前 file 你需要 关闭 它,如果你不 关闭 它会 return一个空文件。

import zipfile
import os
from flask import send_file

@app.route('/download_all')
def download_all():
    zipf = zipfile.ZipFile('Name.zip','w', zipfile.ZIP_DEFLATED)
    for root,dirs, files in os.walk('output/'):
        for file in files:
            zipf.write('output/'+file)
    zipf.close()
    return send_file('Name.zip',
            mimetype = 'zip',
            attachment_filename= 'Name.zip',
            as_attachment = True)

html我简单的调用路由:

<a href="{{url_for( 'download_all')}}"> DOWNLOAD ALL </a>

我希望这对某些人有所帮助。 :)

基于上面@desfido 的回答,这里有一些不涉及使用 zip 的代码实现,而是下载两个不同的文件:

from requests_toolbelt import MultipartEncoder

def make_calculation(arg1, arg2):
    '''Does some calculations.
    input: arg1 - string, arg2- string
    puts results in two different dataframes
    and stores them in two different files,
    returns the names of those two files'''
    return filename1, filename2

@app.route('test_app', methods=['GET', 'POST'])
def test_app():
    form = Form1()
    if form.validate_on_submit():
        f1, f2 = make_calculation(str(form.input_1.data), str(form.input_2.data))
        m = MultipartEncoder({
           'field1': (f1, open(f1, 'rb'), 'text/plain'),
           'field2': (f2, open(f2, 'rb'), 'text/plain')
        })
        return Response(m.to_string(), mimetype=m.content_type)
   return render_template('test_app.html', form=form)

你也可以试试这个,使用 zip 模块 --

import zipfile
from os.path import basename

UPLOAD_PATH = <upload_location>
base_files = ["file1.csv", "file2.csv"]
  
with zipfile.ZipFile(UPLOAD_PATH + 'Test.zip', 'w') as zipF:
    for file in base_files:
        zipF.write(UPLOAD_PATH + file, basename(UPLOAD_PATH + file), compress_type=zipfile.ZIP_DEFLATED)
zipF.close()
return send_file(METAFILE_UPLOADS+'Test.zip', mimetype='zip', attachment_filename='Test.zip', as_attachment=True)