Gubb
Gubb

Reputation: 13

Python, Flask: TypeError: 'NoneType' object has no attribute '__getitem__' for filled form

I have looked through previous questions involving the same error, but have not managed to find a working solution for my problem. I have a form in my html code (as part of a single-page-application) that I wish to submit to my python server through ajax.

the form in details.html:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>A Title</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">`  
<link href= {{ url_for("static",filename="css/bootstrap.min.css") }} rel="stylesheet" media="screen">
</head>
<body>

<div>
<form method="post"> 
    <label for="address">Address</label>
    <input class="form-control" type="text" name="address">

    <label for="postalcode">Postal Code</label>
    <input class="form-control" type="text" name="postalcode"><br>

    <label for="city">City</label>
    <input class="form-control" type="text" name="city">

    <label for="country">Country</label>
    <input class="form-control" type="text" id="country_indicator" placeholder="Country" name="country"> 

    <button id="submitForm" type="submit">Submit</button>

</form>
</div>

<script src="//code.jquery.com/jquery-1.11.2.min.js"></script>
<script src={{ url_for("static", filename="js/bootstrap.min.js") }}></script>
<script src={{ url_for("static", filename="js/details.js") }}></script>
</body>
</html>

If I remove 'method="post"' from the html form, the page empties the forms and reloads, but with it I get the above mentioned error, even when the form is fully filled out. My guess is that something between the form and the JS is not working as the request.json always returns NoneType objects.

details.js:

$(document).ready(function() {

$("#submitForm").click(function(){

    var address = $("#address").val();
    var postalcode = $("#postalcode").val();
    var city = $("#city").val();
    var country = $("#country").val();
    console.log(address);

    var details = {
        "address" : address,
        "postalcode" : postalcode,
        "city" : city,
        "country" : country
    }
    console.log(details.city);

    $.ajax({
        type: "POST",
        url: "/details",
        data: JSON.stringify(details, null, '\t'),
        contentType: 'application/json;charset=UTF-8',
        success: function(result) {
            console.log(result)
        }
    })
    })
})

Note: I added the console.log for troubleshooting, but no text appears in the js-console, which is why I believe the problem appears already before this point.

the relevant app.route in my .py file: I am not yet using the values from details.js, I just wish to see that something is actually sent. This is why I only return "ok" for now.

@app.route('/details', methods=['GET', 'POST'])
def details():
  if request.method == "POST":
    print(request.json['address']) # . TypeError: 'NoneType' object has no attribute '__getitem__' - crash appears here.
    return "ok")
return render_template("details.html")

So because of some problem in the previous steps, the object sent to the .py file is NoneType I assume. I am very new to python and JS, so any pointers would be greatly appreciated. Thank you in advance!

Edit: I also encountered "uncaught ReferenceError: $ is not defined" now from the javascript console, but moving the jquery- to the head solved that problem

Upvotes: 1

Views: 3922

Answers (1)

pmccallum
pmccallum

Reputation: 808

Doh! The data isn't being sent to the server properly! I've rewritten some of your code below. I hope you don't mind, but the form will now submit with ordinary post variables instead of JSON.

@app.route('/details', methods=['GET', 'POST'])
def details():
    # This is our new method, notice it's a bit streamlined.

    if request.method == "POST":
        # We can get the post data using request.form.get(). The first variable is the name="" attribute in HTML, and the second is the default value if it wasn't found in the data.
        return "The address was %s" % request.form.get('address', 'not provided! :O')
    return render_template("base.html")

Now for the Javascript!

$(document).ready(function() {
$("#submitForm").click(function(e){

    // Prevent the HTML page from submitting the form since we're doing this by AJAX. This would cause duplications and other issues.
    e.preventDefault();

    // Get a FormData object from the page
    var data = new FormData($('form')[0]);

    // You don't HAVE to send your data by JSON, and in this instance it will be easier not to
    $.ajax({
        type: "POST",
        url: "/details",
        data: data,
        processData: false,
        contentType: false,
        success: function(result) {
            console.log(result)
        }
    })
    })
})

Hope this helps! Don't forget to mark the answer as solved if this fixes it for you. :)

Upvotes: 1

Related Questions