Python 使用 Flask 上传和下载文件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/27628053/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Uploading and Downloading Files with Flask
提问by User1996
I'm trying to write a really simply webapp with PythonAnywhere and Flask that has lets the user upload a text file, generates a csv file, then lets the user download the csv file. It doesn't have to be fancy, it only has to work. I have already written the program for generating the csv from a txt file on the drive.
我正在尝试使用 PythonAnywhere 和 Flask 编写一个非常简单的 web 应用程序,它允许用户上传文本文件,生成 csv 文件,然后让用户下载 csv 文件。它不一定是花哨的,它只需要工作。我已经编写了从驱动器上的 txt 文件生成 csv 的程序。
Right now, my function opens the file on the drive with:
现在,我的函数使用以下命令打开驱动器上的文件:
with open(INPUTFILE, "r") as fname:
and writes the csv with:
并用以下内容写入 csv:
with open(OUTPUTFILE, 'w') as fname:
with INPUTFILE and OUTPUTFILE being filename strings.
INPUTFILE 和 OUTPUTFILE 是文件名字符串。
Would it be better for me to handle the files as objects, returned by the flask/html somehow?
将文件作为对象处理,由烧瓶/html 以某种方式返回对我来说会更好吗?
I don't know how to do this. How should I structure this program? How many HTML Templates do I need? I would prefer to work on the files wihthout saving them anywhere but if I have to save them to the PythonAnywhere directory, I could. How can I do that?
我不知道该怎么做。我应该如何构建这个程序?我需要多少个 HTML 模板?我更喜欢处理文件而不将它们保存在任何地方,但如果我必须将它们保存到 PythonAnywhere 目录中,我可以。我怎样才能做到这一点?
采纳答案by Giles Thomas
PythonAnywhere dev here. This is a good question about Flask and web development in general rather than specific to our system, so I'll try to give a generic answer without anything specific to us :-)
PythonAnywhere 开发者在这里。这是一个关于 Flask 和 Web 开发的好问题,而不是特定于我们的系统,所以我将尝试给出一个通用的答案,而不是针对我们的任何内容:-)
There are a few things that I'd need to know to give a definitive answer to your question, so I'll start by listing the assumptions I'm making -- leave me a comment if I'm wrong with any of them and I'll update the answer appropriately.
为了对您的问题给出明确的答案,我需要知道一些事情,所以我将首先列出我所做的假设 - 如果我对其中任何一个有错误,请给我留言,我会适当地更新答案。
- I'm assuming that the files you're uploading aren't huge and can fit into a reasonable amount of memory -- let's say, smaller than a megabyte.
- I'm assuming that the program that you've already written to generate the CSV from the text file is in Python, and that it has (or, perhaps more likely, could be easily changed to have) a function that takes a string containing the contents of the text file, and returns the contents that need to be written into the CSV.
- 我假设您上传的文件不是很大,并且可以放入合理的内存量 - 比方说,小于 1 兆字节。
- 我假设您已经编写的用于从文本文件生成 CSV 的程序是在 Python 中编写的,并且它具有(或者,更可能的是,可以很容易地更改为具有)一个函数,该函数采用包含以下内容的字符串文本文件的内容,并返回需要写入CSV的内容。
If both of those are the case, then the best way to structure your Flask app would be to handle everything inside Flask. A code sample is worth a thousand words, so here's a simple one I put together that allows the user to upload a text file, runs it through a function called transform
(which is where the function from your conversion program would slot in -- mine just replaces =
with ,
throughout the file), and sends the results back to the browser. There's a live version of this app on PythonAnywhere here.
如果这两种情况都是如此,那么构建 Flask 应用程序的最佳方式就是处理 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
Regarding your other questions:
关于您的其他问题:
- Templates: I didn't use a template for this example, because I wanted it all to fit into a single piece of code. If I were doing it properly then I'd put the stuff that's generated by the
form
view into a template, but that's all. - Can you do it by writing to files -- yes you can, and the uploaded file can be saved by using the
save(
filename)
method on thefile
object that I'm using thestream
property of. But if your files are pretty small (as per my assumption above) then it probably makes more sense to process them in-memory like the code above does.
- 模板:我没有在这个例子中使用模板,因为我希望所有这些都适合一段代码。如果我做得正确,那么我会将
form
视图生成的内容放入模板中,但仅此而已。 - 你能通过写入文件来做到这一点吗——是的,你可以,上传的文件可以通过在我使用的对象上使用
save(
文件名)
方法来保存。但是,如果您的文件非常小(根据我上面的假设),那么像上面的代码那样在内存中处理它们可能更有意义。file
stream
I hope that all helps, and if you have any questions then just leave a comment.
希望对大家有所帮助,如果您有任何疑问,请发表评论。
回答by teosbpl
Better to add
最好加上
response.headers["Cache-Control"] = "must-revalidate"
response.headers["Pragma"] = "must-revalidate"
response.headers["Content-type"] = "application/csv"
If you don't add the content type, FF 48.0 reported it as html and opened Save dialog once for HTML and then for CSV. If you don't add Cache-Control your result may get cached, and if you serve active content this is not what you want. If you use must-revalidate with no age, it will effectively serve as no-cache - see hereand herefor an explanation.
如果您不添加内容类型,FF 48.0 会将其报告为 html 并为 HTML 打开一次保存对话框,然后为 CSV 打开一次。如果您不添加 Cache-Control,您的结果可能会被缓存,如果您提供活动内容,这不是您想要的。如果您使用没有年龄的 must-revalidate,它将有效地用作无缓存 - 请参阅此处和此处以获取解释。