Flask upload files

Flask upload files

这个note是关于怎么用flask上传文件。包含了两种不同的上传文件的方式。第一种是通过HTML <form></form>直接上传。另一种通过API的办法上传。两种方法都会详细解释。等学会了怎么使用之后,大家可以自己做一个自己的file server。当然现成的file server有很多,比如NextCloud这一类的,都是非常成熟的框架,大家如果不想造轮子可以直接用现成的框架来搭建。

通过Flask HTML直接上传

上传文件一般只需要三步:

  1. 第一步就是定义HTML的文件:

    需要说几点:

    • 因为是上传文件,所以在form里面必须定义enctype="multipart/form-data"不然没办法上传文件
    • 然后是<input>, input 的type一定要是file 才可以选中文件,不然没办法使用。然后是如果想上传多个file的话需要申明multiple才可以选中多个文件同时长传。
    1
    2
    3
    4
    <form method="post" enctype="multipart/form-data" >
    <input type="file" name="file" multiple>
    <button class="submitI" >Upload Image</button>
    </form>
  2. Upload Image 按钮被点击后,通过request对象上的files获取文件。和以前用request获取表单值一样,使用input字段的name值获取:

    1
    2
    3
    4
    5
    # 当input 不是multiple时候可以使用这个,这个表示只上传一个file
    file = request.files['file']

    # 当input是multiple的时候表示有多个文件上传
    for file in request.files.getlist("file"):
  3. 使用file.save()保存文件,指定保存的地址及文件名:

    1
    file.save(str(path + filename))

详细HTML代码:

1
2
3
4
<form method="post" enctype="multipart/form-data" >
<input type="file" name="file" multiple>
<button class="submitI" >Upload Image</button>
</form>

详细Python代码,给大家说一下为什么要用static的文件夹存文件:因为如果flask是在服务器上运行的话,需要访问服务器的资源的时候只有static可以被外部访问,所有一般把照片,js这些文件都存在static的文件夹下,以方便外部调用。:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
from flask import Flask, render_template, request
import os

app = Flask(__name__)

# 有两种方法来获取路径
# TODO 第一种是绝对路径
# 得到当前路径
# basedir = os.getcwd()
# target = os.path.join(basedir, 'static/files')
# if not os.path.isdir(target):
# os.mkdir(target)

# TODO 第二种是相对路径
target = 'static/files'
if not os.path.isdir(target):
os.mkdir(target)


# 允许上传的类型
ALLOWED_EXTENSIONS = {'txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif'}

# 检查是否符合上传文件类型
def allowed_file(filename):
return '.' in filename and \
filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS


@app.route('/', methods=["POST", "GET"])
def index():

# 如果<input>设置的是单个文件的话,可以使用下面这行代码直接得到file
# 可以直接用这行代码替换for语句
# file = request.files.get('file')

for file in request.files.getlist("file"):
# 检查是否符合上传类型
if file and allowed_file(file.filename):
filename = file.filename
# 把路径和文件名链接起来
filepath = "/".join([target,filename])
file.save(filepath)
return render_template("upload.html")

app.run(debug=True)

因为之前测试的时候已经上传了一个文件,所有在static/files下面有三个文件

怎么通过Flask下载文件

可以直接通过send_file来直接下载文件,这个不好截图,直接上代码吧,亲测可以执行,绝对能用。具体代码如下:

1
2
3
4
5
6
7
8
9
10
11
from flask import send_from_directory
@app.route('/download/<filename>', methods=["GET", "POST"])
def download(filename):
filepath = "static/files/"
try:
# as_attachment=True 一定要写,不然会变成打开,而不是下载
# 这个是根据文件夹来send file的, 所以你要下载什么文件就要使用什么路径
# 比如我们使用的是 "static/files/"
return send_from_directory(filepath, filename, as_attachment=True)
except Exception:
return redirect(url_for('index'))

Flask API upload files

通过API的方式开上传文件。在使用API上传文件的时候需要在前端用到FormDataFormData的作用就是异步传输二进制文件。FormData的使用场景就是表单提交。

怎么使用FormData

  1. 首先创建一下FormData对象:

    1
    var formData = new FormData();
  2. 把HTML表单用来初始化FormData,以及FormData的一些常见用法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    <form id="form" method="post" enctype="multipart/form-data" >
    <input type="text" name="username" id="username">
    <input type="text" name="password" id="password">
    </form>

    <script>
    var formData = new FormData(document.getElementById("form"));
    // 这样formData就储存了username和password
    // 可以通过get的方式得到value
    var username = formData.get("username");
    var password = formData.get("password")
    // 也可以使用append的方式添加value
    formData.append("token", "12334")
    // 可以通过set修改value
    formData.set("token", "1");
    // 可以通过delete删除元素
    formData.delete("token")
    </script>

Flask-RESTful API

后端Flask我们依然是通过reqparse.RequestParser()的方式获取上传的文件。前端则是通过FormData的方式来上传文件。

详细代码:

  • 如果想上传多个文件在add_argument的时候需要声明action='append'才能获取到多个文件否则只能获取一个文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
from flask import Flask, jsonify, make_response, request
from flask_restplus import Api, reqparse, abort, Resource
from werkzeug.datastructures import FileStorage
import os


app = Flask(__name__)
api = Api(app)
app.config['SECRET_KEY'] = 'WHATEVER'

basedir = os.getcwd()

upload = api.namespace('upload', description="Upload files API")

@upload.route("/", strict_slashes=False)
class Upload(Resource):

def post(self):
parser = reqparse.RequestParser()
parser.add_argument('file', location='files',type=FileStorage, required=True, action='append')

args = parser.parse_args()
uploaded_file = args.get('file')

target = os.path.join(basedir, 'static/files')
if not os.path.isdir(target):
os.mkdir(target)

for file in uploaded_file:
filepath = "/".join([target,file.filename])
file.save(filepath)

app.run(debug=True)

JQuery upload files

前端则使用了JQuery来上传文件。使用的是FormData的格式来上传文件。详细代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<form action="" id="formContent" method="post" enctype="multipart/form-data" >
<input type="file" name="file" multiple required id="upload">
<button class="submitI" >Upload Image</button>
</form>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script type="text/javascript">
$("#formContent").submit(function(e){
e.preventDefault();
console.log(this)
var formdata = new FormData(this);
$.ajax({
url: "http://127.0.0.1:5000/upload/",
type: "POST",
data: formdata,
mimeTypes:"multipart/form-data",
contentType: false,
cache: false,
processData: false,
success: function(data){
console.log(data);
},
error: function(data){
console.log(data);
}
});
});
</script>

Flask API download files

关于通过flask api下载文件的方式和前面讲的基本上差不多,就是改成了API的写法。详细代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
from flask import Flask, jsonify, make_response, request
from flask_restplus import Api, reqparse, abort, Resource
from werkzeug.datastructures import FileStorage
import os


app = Flask(__name__)
api = Api(app)
app.config['SECRET_KEY'] = 'WHATEVER'

basedir = os.getcwd()

upload = api.namespace('upload', description="Upload files API")

@upload.route("/", strict_slashes=False)
class Upload(Resource):

def post(self):
parser = reqparse.RequestParser()
parser.add_argument('file', location='files',type=FileStorage, required=True, action='append')

args = parser.parse_args()
uploaded_file = args.get('file')

target = os.path.join(basedir, 'static/files')
if not os.path.isdir(target):
os.mkdir(target)

for file in uploaded_file:
filepath = "/".join([target,file.filename])
file.save(filepath)

def get(self):
parser = reqparse.RequestParser()
parser.add_argument('filename', type=str)
args = parser.parse_args()
filename = args.get("filename")

filepath = "static/files/"
try:
# as_attachment=True 一定要写,不然会变成打开,而不是下载
# 这个是根据文件夹来send file的, 所以你要下载什么文件就要使用什么路径
# 比如我们使用的是 "static/files/"
return send_from_directory(filepath, filename, as_attachment=True)
except Exception:
return make_response("Error", 403)

app.run(debug=True)

在浏览器内输入以下命令就可以开始下载文件:

1
http://127.0.0.1:5000/upload?filename=sqlmap.pdf
----- End Thanks for reading-----