如何使用 AJAX 调用和 Flask 上传 (csv) 文件

How to upload a (csv) file with an AJAX call and Flask

我正在更新一个使用 AJAX 并决定使用 Flask 的旧项目。对于我当前正在处理的特定页面,我需要能够上传 CSV 文件并读取文件中的数据(无需保存)。我还有其他几个使用 AJAX 工作的页面,但它们 return 将数据返回给 Flask(例如,它是什么学期,它是哪一年,等等)。理想情况下,我希望能够上传 CSV 文件并读取表单数据(我在下面调用的变量 formDatamyFormData)。

我找到了 this post 并基于它建立了我的 MWE,但是当我查看 request.files 时,我得到了一个空字典。这是我的代码:

run.py:

import os
from app import app
if __name__ == "__main__":
    port = int(os.environ.get("PORT", 5000))
    app.run(host='0.0.0.0', port=port, debug=True)

__init__.py:

from flask import Flask, session
import flask_excel as excel

from fileUpload import fileUpload_bp

def create_app():
    app = Flask(__name__, template_folder="templates")
    app.secret_key = 'flask-ajax file upload test'

    app.register_blueprint(fileUpload_bp)
    excel.init_excel(app)
    return app

app = create_app()

file_upload.py:

from flask import Flask, render_template, request, Blueprint

fileUpload_bp=Blueprint('fileUpload',__name__)

@fileUpload_bp.route('/fileUpload',methods=['GET','POST'])
def fileUpload():
    if request.method=="POST":
        print(request.files)
        
    return render_template("fileUpload.html")

fileUpload.html:

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>file upload test</title>
    <script type="text/javascript"
            src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
    <script type="text/javascript" 
            src="static/scripts/fileUpload.js"></script>
  </head>

  <body>
    <form action="javascript:fileUpload()" method="POST" enctype="multipart/form-data">
      <input type="file" id="file_upload_data"><br>
      <input type="text" id="form_data" value="sample data">
      <button type="submit">Upload</button>
    </form>
  </body>

</html>

fileUpload.js:

function fileUpload()
{
    var formData=new FormData($("file_upload_data")[0]);
    var myFormData={form_data: $("#form_data").val()};
    $.ajax({
        type: 'post',
        dataType: 'html',
        url: 'fileUpload',
    async: false,
    data: formData,
    contentType: false,
    cache: false,
    processData: false,
        success: function (data){
            console.log('Success');
        },
        error: function(response, status, xml) {
            console.log('failure');
        }
    });
}

一些附加信息:这是一个更大项目的一部分,这就是我使用蓝图和 flask_excel 的原因。我看到人们建议使用 AJAX 以外的其他东西,但我正在尝试使用 Flask 将页面 运行 与 python3 一起使用,而不重写已经存在的所有内容。

为了序列化表单,输入字段必须具有名称属性。
我在下面的最小示例中使用了表单的提交事件。事件侦听器在文档完全加载时注册。提交表单时,表单数据被序列化并通过ajax.

发送
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Upload</title>
  </head>
  <body>

    <form name="upload-form" method="post" enctype="multipart/form-data">
      <input type="file" name="file">
      <button type="submit">Upload</button>
    </form>

    <script type="text/javascript"
            src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>

    <script type="text/javascript">
    $(document).ready(function() {
      // Register the listener for submit events.
      $('form[name="upload-form"]').submit(function(evt) {
        // Prevent the form from default behavior.
        evt.preventDefault();
        // Serialize the form data. The entire form is passed as a parameter.
        const formData = new FormData($(this)[0]);
        // Send the data via ajax.
        $.ajax({
          type: 'post',
          url: '/upload',
          data: formData,
          contentType: false,
          cache: false,
          processData: false,
        }).done(function(data) {
          console.log('success');
        }).fail(function(xhr, status, error) {
          console.error('error');
        });
      });
    });
    </script>

  </body>
</html>

server-side 代码基本保持不变。但是,出于清洁的原因,我建议您将 ajax 请求的端点与 return html.

请求的端点分开
from flask import Flask
from flask import make_response, render_template, request

app = Flask(__name__)

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/upload', methods=['POST'])
def upload():
    print(request.files)
    return make_response('', 200)