【问题标题】:Uploading and Downloading Files with Flask使用 Flask 上传和下载文件
【发布时间】:2015-02-22 01:11:18
【问题描述】:

我正在尝试使用 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 目录,我可以。我怎样才能做到这一点?

【问题讨论】:

    标签: python python-2.7 file-upload flask pythonanywhere


    【解决方案1】:

    PythonAnywhere 在这里开发。这是一个关于 Flask 和 Web 开发的好问题,而不是特定于我们的系统,所以我将尝试给出一个通用的答案,而不是针对我们的任何特定内容:-)

    我需要知道一些事情才能对您的问题给出明确的答案,所以我将首先列出我所做的假设 - 如果我有任何错误,请给我评论其中,我会适当地更新答案。

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

    如果这两种情况都是如此,那么构建 Flask 应用程序的最佳方式就是处理 Flask 中的所有内容。一个代码示例值一千字,所以这是我放在一起的一个简单的示例,它允许用户上传一个文本文件,通过一个名为 transform 的函数运行它(这是转换程序中的函数将插入的位置 - - 我的只是将整个文件中的= 替换为,),并将结果发送回浏览器。 There's a live version of this app on PythonAnywhere here.

    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 视图生成的内容放入模板中,仅此而已。
    • 你能不能通过写入文件来做到这一点——是的,你可以,上传的文件可以通过使用 file 对象上的 save( 上的 ) 方法保存'我正在使用 stream 的属性。但是,如果您的文件非常小(根据我上面的假设),那么像上面的代码那样在内存中处理它们可能更有意义。

    希望对大家有所帮助,如果有任何问题,请发表评论。

    【讨论】:

    • 很好的答案。尝试在这里应用它的元素:stackoverflow.com/q/35496045/1389110
    • 我尝试了python无处不在的演示,它不工作,我得到:内部服务器错误服务器遇到内部错误,无法完成您的请求。要么服务器超载,要么应用程序出错。
    • 我不会用文件变量为文件类型起别名。
    【解决方案2】:

    最好添加

    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,它将有效地用作无缓存 - 请参阅 herehere 以获得解释。

    【讨论】:

      猜你喜欢
      • 2018-03-02
      • 2017-04-10
      • 2011-10-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-08
      • 1970-01-01
      • 2014-08-28
      • 1970-01-01
      相关资源
      最近更新 更多