关于设置request 方法为form还是files

基本区别

  • 例如,下列关于文件上传的前端和python后端代码为:
    前端代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <!DOCTYPE html>
    <html>
    <head>
    <title>Upload File</title>
    </head>
    <body>
    <form action="/upload" method="post" enctype="multipart/form-data">
    <label for="file">File:</label>
    <input type="file" id="file" name="file">
    <br>
    <input type="submit" value="Upload">
    </form>
    </body>
    </html>

    后端:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    from flask import Flask, request, redirect, url_for

    app = Flask(__name__)
    app.secret_key = 'your_secret_key'

    @app.route('/upload', methods=['POST'])
    def upload():
    file = request.files.get('file')
    if file:
    filename = file.filename
    file.save(f'uploads/{filename}')
    return f'File uploaded successfully: {filename}'
    return 'No file uploaded'

    if __name__ == '__main__':
    app.run(debug=True)
  • 这里可见在upload()函数中,request请求后写为:files.get方法,为什么会写作files.get而不是form.get?
    关键点在编码方式:

    enctype=multipart/form-data
    该种编码方式将文件以二进制方式进行解析,适合传输如视频音频格式的文件,由于该种文件在请求体中的呈现方式类似于如下形式:

    1
    2
    3
    4
    5
    6
    7
    8
    --boundary_123456
    Content-Disposition: form-data; name="file"; filename="photo.jpg"
    Content-Type: image/jpeg

    [二进制文件流...]
    --boundary_123456--
    xxxx
    --boundary_123456--
  • 而并非为enctype=application/x-www-form-urlencoded,即请求体为类似于:k1=a&k2=b形式,
    所以需要使用files.get形式而非form.gets

  • 底层原理:

  • Flask的解析逻辑:

    Flask 根据 enctype 的类型自动解析请求体:
    对普通文本表单(application/x-www-form-urlencoded):
    数据被解析到 request.form(一个字典结构,只存文本键值对)。
    对文件上传表单(multipart/form-data):
    Flask 将 文本字段 的数据放在 request.form,
    文件数据则被转移到 request.files(存的是文件对象)。

特殊情况

Q:如果表单既有文件又有文本怎么办?
A:比如上传文件且填写描述:

1
2
3
4
<form action="/upload" method="POST" enctype="multipart/form-data">
<input type="text" name="description">
<input type="file" name="file">
</form>

外部浏览器打开
后端代码

1
2
3
4
@app.route('/upload', methods=['POST'])
def process():
description = request.form.get('description') # 用form
file = request.files.get('file') # 用files

关于Flask库中ORM设计思想

  • 通俗来说,就是用简单的python代码来代替容易拼错的sql语句:
    使用普通的sqlite3库:

    1
    data = cursor.execute("SELECT * FROM user WHERE username='alice';")
  • 使用 Flask-SQLAlchemy库:

    1
    id = db.Column(db.Integer,primary_key = True)

    这里即使用易懂的python语言而非sql语言创建了一个键username,并将其定义为主键,数据类型为整数。
    完整代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    import flask
    from flask_sqlalchemy import SQLAlchemy

    app = flask.Flask(__name__)
    app.config['SECRET_KEY'] = 'thisismysecretkey'
    app.config['SQLALCHEMY_DATABASE_URI'] ='sqlite:///test.db'#创建了一个数据库文件
    db = SQLAlchemy(app)

    class User(db.Model):#定义了一个表的结构
    id = db.Column(db.Integer, primary_key=True)#创建了一个整数键,名字为"id"
    username = db.Column(db.String(80), unique=True, nullable=False)
    email = db.Column(db.String(120), unique=True, nullable=False)

    def __repr__(self):
    return f'<User {self.username}>'

    加入新数据:

    1
    2
    3
    new_user = User(username="Alice",email="123456@qq.com")
    db.session.add(new_user)
    db.session.commit

    多说几句,这里为什么要使用session?
    首先可以自行前往wiki上了解”事务”这个计算机数据库概念,在数据库被操作时,数据库的记录对象会被锁定,只能添加读取或者删除,只有事务结束之后才可以进行下一步操作,防止出现数据丢失的情况。

    取出数据:

    1
    2
    user = User.query.filter_by(username='Alice').first()  # 定位数据
    print(user) # 输出: <User Alice>

    ….(其他对应操作可以去看菜鸟教程)