1

Trying to understand what I'm doing wrong here when using JQuery AJAX POST request to send both form data and an attached file to a Flask endpoint.

The basic Flask view that I'm still building looks like this:

@main.route('/videoupload', methods=['GET','POST'])
def videoupload():
    if request.method == 'POST':
        ajaxpost = request.form['m_data']
        print(ajaxpost)
    return render_template('videoupload.html')

The JQuery for the form and attached file looks like this:

$("#submit_btn").click(function() {  
        var proceed = true;

        if(proceed) //everything looks good! proceed...
        {
            //data to be sent to server
            var m_data = new FormData();    
            m_data.append( 'video_title', $('input[name=videoTitle]').val());
            m_data.append( 'video_description', $('input[name=videoDescription]').val());
            m_data.append( 'video_tags', $('input[name=videoTags]').val());
            m_data.append( 'file_attach', $('input[name=file_attach]')[0].files[0]);
            //instead of $.post() we are using $.ajax()
            //that's because $.ajax() has more options and flexibly.
            $.ajax({
              url: '/videoupload',
              data: m_data,
              processData: false,
              contentType: false,
              type: 'POST',
                  //dataType:'json',
              datatype:'json',
              success: function(response){
                 //load json data from server and output message     
                if(response.type == 'error'){ //load json data from server and output message     
                    output = '<div class="error">'+response.text+'</div>';
                }else{
                    output = '<div class="success">'+response.text+'</div>';
                }
                $("#videoform #form_results").hide().html(output).slideDown();
              }
            });        
        }
    });

Using Firebug and the Net window, I can confirm that data entered in the fields of the form and the attached file are being appended to the FormData() object.

When the user clicks Submit button, I get the following error in the Console:

> POST http://127.0.0.1:8000/videoupload 400 (BAD REQUEST)
send @ jquery.js:9664
m.extend.ajax @ jquery.js:9215
(anonymous function) @ videoupload:137
n.event.dispatch @ jquery.min.js:3
r.handle @ jquery.min.js:3

Navigated to http://127.0.0.1:8000/videoupload?videoTitle=asdf&videoDescription=asdfasdfasdfasdfasdf&videoTags=ZcZXcZXcZXcZXC&file_attach=ScreenCaptureProject1.mp4

In the Terminal window running Flask app (using Gunicorn) running in debug mode, no errors appear:

[2016-05-20 00:18:21 -0400] [27033] [DEBUG] POST /videoupload
POST CALLED
[2016-05-20 00:18:24 -0400] [27033] [DEBUG] GET /videoupload

It seems as though the AJAX is pinging the Flask view with a POST request. Am I handling the form incorrectly in the Flask view? Is there something incorrect with the JQuery AJAX POST request that Flask doesn't like?

0

1 Answer 1

1

request.form is a MultiDict with the key-value pairs of the received form data.

You are attempting to index this dictionary using the string 'm_data' as a key, but it looks like 'm_data' is just the name of your JavaScript variable and not actually a key of the form data. If 'm_data' is not a valid key this would raise an exception.

To quote the Werkzeug documentation on MultiDicts:

"From Werkzeug 0.3 onwards, the KeyError raised by this class is also a subclass of the BadRequest HTTP exception and will render a page for a 400 BAD REQUEST if caught in a catch-all for HTTP exceptions."

To help debug this route, you can wrap your python code in a try-except block:

@main.route('/videoupload', methods=['GET','POST'])
def videoupload():
    if request.method == 'POST':
        try:
            [your code]
        except Exception, e:
            print e
    return render_template('videoupload.html')

Then you can check whether a KeyError appears in the error logs (or console if you're running the Flask test server locally).

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks for the background info and doc links. Unfortunately the error try/except catches isn't that informative, just getting 400: Bad Request. However, when I try ajaxpost = request.form['video_title'] I get undefined in the console. So maybe I just need to keep digging into how to properly access the key/values in m_data object
You can print the dictionary request.form to see what Flask has stored there.
Yeah, tried that earlier today and it definitely helped. It's empty: ImmutableMultiDict([('videoTitle', u'undefined'), ('videoTags', u'undefined'), ('videoDescription', u'undefined')]) Interestingly, all the values are winding up on the url of the same page as a query string, like the AJAX is adding all the values that should be in the immutablemultidict to the URL
Take a look at this thread. It looks like you may have to explicitly set the Content-Type header to 'multipart/form-data' when configuring the AJAX request. If you don't mind jQuery serializing the data and passing it as a query string, you should examine request.values (see docs) rather than request.form.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.