使用Flask上传和下载文件

29
我想在PythonAnywhere和Flask上编写一个非常简单的Web应用程序,使用户可以上传一个文本文件、生成一个csv文件,然后让用户下载该csv文件。它不需要很花哨,只需正常工作即可。我已经编写了从驱动器上的txt文件生成csv的程序。
现在,我的函数使用以下代码在驱动器上打开文件:
with open(INPUTFILE, "r") as fname:

并使用以下内容编写csv:

with open(OUTPUTFILE, 'w') as fname:

假设输入文件名为INPUTFILE,输出文件名为OUTPUTFILE。

对于我来说,是否最好将这些文件处理为由flask/html返回的对象?

我不知道如何做到这一点。我应该如何构建这个程序?我需要多少HTML模板?我宁愿在不保存它们的情况下直接使用这些文件,但如果必须将它们保存到PythonAnywhere目录中,我可以这样做。我该怎么做?

2个回答

37

我是PythonAnywhere的开发人员。这是一个关于Flask和Web开发的好问题,不仅适用于我们的系统,因此我会尝试提供通用答案 :-)

要给出明确答案,我需要了解一些信息,所以我将首先列出我的假设 - 如果我其中任何一个假设不正确,请在评论中告诉我,我将相应地更新回答。

  • 我假设您上传的文件不是很大,并且可以放入合理的内存空间中--假设小于1兆字节。
  • 我假设从文本文件生成CSV的程序是使用Python编写的,并且它具有(或者更可能的是,可以轻松更改为具有)一个函数,该函数接受包含文本文件内容的字符串,并返回需要写入CSV的内容。

如果两者都成立,则最佳方法是在Flask中处理一切。下面是一个简单的代码示例,允许用户上传文本文件,通过名为transform的函数运行它(其中包括从转换程序获取的函数 - 我的只是替换整个文件中的=,),并将结果发送回浏览器。在PythonAnywhere这里有一个实时版本的应用程序

from flask import Flask, make_response, request

app = Flask(__name__)

def transform(text_file_contents):
    return text_file_contents.replace("=", ",")


@app.route('/')
def form():
    return """
        <html>
            <body>
                <h1>Transform a file demo</h1>

                <form action="/transform" method="post" enctype="multipart/form-data">
                    <input type="file" name="data_file" />
                    <input type="submit" />
                </form>
            </body>
        </html>
    """

@app.route('/transform', methods=["POST"])
def transform_view():
    request_file = request.files['data_file']
    if not request_file:
        return "No file"

    file_contents = request_file.stream.read().decode("utf-8")

    result = transform(file_contents)

    response = make_response(result)
    response.headers["Content-Disposition"] = "attachment; filename=result.csv"
    return response

关于您的其他问题:

  • 模板:我在这个例子中没有使用模板,因为我想让所有内容都适合单个代码块。如果我做得正确的话,那么我会将由form视图生成的内容放入模板中。
  • 您可以通过写入文件来实现吗?是的,您可以,而且上传的文件可以使用我正在使用的stream属性的file对象上的save(filename)方法保存。但是,如果您的文件相当小(根据我上面的假设),那么像上面的代码一样在内存中处理它们可能更有意义。

希望这些都有所帮助,如果您有任何问题,请留言。


很棒的答案。正在尝试将其元素应用于此处:http://stackoverflow.com/q/35496045/1389110 - Pyderman
我尝试了Python Anywhere的演示,但它无法工作,我收到了“内部服务器错误”的提示。服务器遇到了内部错误,无法完成您的请求。可能是服务器过载或应用程序出现错误。 - Mostafa
1
我不会将文件类型与文件变量设置为别名。 - K. Brafford

10
更好的方法是添加。
response.headers["Cache-Control"] = "must-revalidate"
response.headers["Pragma"] = "must-revalidate"
response.headers["Content-type"] = "application/csv"

如果您未添加内容类型,FF 48.0报告它为html,并打开保存对话框一次用于HTML,然后再用于CSV。 如果您不添加Cache-Control,则可能会缓存结果,如果提供活动内容,则不是您想要的结果。如果您使用must-revalidate而没有设置age,则将有效地作为no-cache - 有关说明,请参见此处以及此处


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接