1

I am uploading an image file to a Flask endpoint using AJAX. I want to send metadata (author, publication date, etc) alongside the file in the same AJAX upload.

My JQuery code looks like:

    $("#upload_btn").click(function() { 
        var fd = new FormData(); 
        var file = $('#file_input')[0].files[0]; 
        // Build AJAX request
        fd.append('file', file);               // This works fine, the file is uploaded
        fd.append('author', 'Test Auth');      // I'd expect this to upload but it doesn't
        fd.append('pub_date', '01 Jan 2018');  // nor this
        $.ajax({ 
            url: '{{ upload_url }}', 
            type: 'post', 
            data: fd, 
            contentType: false, 
            processData: false, 
            xhr: function () {
                var xhr = new window.XMLHttpRequest();
                xhr.upload.addEventListener("progress", function (evt) {
                    if (evt.lengthComputable) {
                        var percentComplete = evt.loaded / evt.total;
                        percentComplete = parseInt(percentComplete * 100);
                        $('#progress').text(percentComplete + '%');
                        $('#progress').css('width', percentComplete + '%');
                    }
                }, false);
                xhr.addEventListener("load", function(evt){ 
                    var results = JSON.parse(xhr.responseText);
                    if(results.result == 'ok'){ 
                        $('#progress_status').text('SUCCESS: Upload complete');
                    } 
                    else{ 
                        $('#progress_status').text('APP ERROR: ' + results.message);
                    } 
                }, false);
                xhr.addEventListener("error", function(jqXHR, textStatus, exception){ 
                    $('#progress_status').text('SYSTEM ERROR');
                }, false);
                return xhr;
            },
        }); 
    }); 

At the Flask endpoint I would have expected to be able to retrieve author using:

    print(request.data['author']) 

or possibly:

    print(request.data.author)

but neither work.

My Flask endpoint code looks like:

@targets.route("/upload_file", methods=["POST"])
def upload_file():
    print("AA: Entered upload_file function")
    print(request.data['author'])
    file = request.files["file"]
    filename = secure_filename(file.filename)
    file_handle = save_user_file(file)
    if file_handle is None:
        results = {"result": "error",
                   "message": "Could not save file",
                   "file_handle": None}
    else:
        results = {"result": "ok",
                   "message": "File uploaded",
                   "file_handle": file_handle}
    return jsonify(results)

The print(request.data['author']) statement raises the error:

TypeError: byte indices must be integers or slices, not str

Obviously data is a blob and I'm not accessing the correct element of the request object.

What approach should I be using to send metadata alongside the uploaded file and retrieve it at the endpoint?

nakb
  • 321
  • 1
  • 3
  • 16
  • The JS is correct. I can only assume the issue lies with how you're accessing the request body through Flask – Rory McCrossan Dec 02 '19 at 15:46
  • Added the current endpoint code. If the JS is correct then it must be that I'm not understanding how to retrieve the data from the request object. – nakb Dec 02 '19 at 16:01

1 Answers1

1

The form data comes attached to the request as request.form, request.data is always a string AFAIK. So just try author = request.form["author"] or something like that.

reptilicus
  • 10,290
  • 6
  • 55
  • 79