Search code examples
jqueryflaskgetrequest

Flask - Getting NoneType when using request.form.get


I know this has been asked several times but unfortunately I'm not being able to fully grasp other answers as my knowledge is still very limited. My attempts have been reduced to basically messing up with the POST and GET methods as well as trying request.form.get(), request.form[] and request.args.get() but I get either the aforementioned error or method not allowed error or bad request error.

I created a simple website where the user chooses two numbers (either 1 or 2), the first from a dropdown list and the second from a ratio option. The output should be the sum of those numbers, however when I click the submit button I keep getting the error

TypeError: unsupported operand type(s) for +: 'NoneType' and 'NoneType'

My python app looks like this:

from flask import Flask, render_template,request
app=Flask(__name__)

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

@app.route('/model',methods=['GET','POST'])
def model():
    first=request.form.get('inputFirst',type=int)
    second=request.form.get('inputSecond',type=int)
    suma=first+second
    return render_template('final.html',suma=suma)

if __name__ == "__main__":
    app.run(debug=True)

Here is the main html file (example.html)

<!DOCTYPE html>
<html>
  <head>
    <title>Example</title>
    <script src="../static/js/jquery-3.2.1.js"></script>
    <script src="../static/js/model.js"></script>
  </head>
  <body>
  <div class="container">
   <div class="jumbotron">
    <form>
      <h2>Choose one number</h2>
      <label for="firstNumber" class="sr-only">First Number</label>
      <select name="inputFirst" id="firstNumber" required>
      <option value="1" label="One">1</option>
      <option value="2" label="Two" selected>2</option>
      </select>

      <h2> Choose another number</h2>   
      <input type="radio" name="inputSecond" id="one1" value="1" required/>
      <label for="one1">1</label>
      <input type="radio" name="inputSecond" id="two2" value="2"/>          
      <label for="two2">2</label>
      <button onclick="location.href='/model'" id="btnModel" class="btn btn-lg btn-primary btn-block" type="button">Run model</button>
    </form>
   </div> 
  </div>
  </body>
</html> 

Here is the model.js file

$(function(){
    $('#btnModel').click(function(){
        $.ajax({
            url: '/model',
            data: $('form').serialize(),
            type: 'POST',
            success: function(response){
            console.log(response);
            },
            error: function(error){
            console.log(error);
            }
        });
    });
});

And for the output, here is the final.htmlfile

<html>
<head>
<h1>RESULT</h1>
</head>
<body>
<h3>The result is: {{suma}} </h3>
</body>
</html>

As a last attempt, I tried to change request.form.get('inputFirst',type=int) by request.form.get('inputFirst',0,type=int) and similarly changing request.form.get('inputSecond',type=int) by request.form.get('inputSecond',0,type=int), in which case the website works, so if I understand correctly the form in example.html is not saving the numbers chosen by the user, however the names inputFirst and inputSecond in the example.html file match the names in the request method from the python file. So I'm not sure what would be the problem.

Any help is appreciated.


Solution

  • jQuery serialize() Method creates a URL encoded text string by serializing form val. What your final requests looks like is

    /model?inputFirst=1&inputSecond=2
    

    and the way to access your values in flask is

    inputFirst = request.values.get('inputFirst')
    inputSecond = request.values.get('inputSecond')
    

    Then you can convert them to integer as the previous answer suggested

    EDIT I will add a basic working example. I have combined my html and javascript, am sure you will know how to separate and improt

    HTML

    <!DOCTYPE html>
    <html>
    <head>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <script>
      $("#myForm").submit(function(e) {
        e.preventDefault();
    });
    
         function upload(){
                $.ajax({
       method: "POST",
       url: "/model",
       data: $('form').serialize(),
       success:function(res){
          var content = res;
            $("div").text(content);
       }
     });
                return false;
    }
    
    
    </script>
    </head>
    <body>
    
    <body>
        <form id="myForm" method="post">
          <h2>Choose one number</h2>
          <label for="firstNumber" class="sr-only">First Number</label>
          <select name="inputFirst" id="firstNumber" required>
          <option value="1" label="One">1</option>
          <option value="2" label="Two" selected>2</option>
          </select>
    
          <h2> Choose another number</h2>   
          <input type="radio" name="inputSecond" id="one1" value="1" required/>
          <label for="one1">1</label>
          <input type="radio" name="inputSecond" id="two2" value="2"/>          
          <label for="two2">2</label>
          <button  id="btnModel" onclick="return upload();">Run model</button>
        </form>
       <div>Submitted info comes here</div>
      </body>
    
    </body>
    </html>
    

    And on my view

    @app.route('/model',methods=['GET','POST'])
    def model():
        if request.method == 'POST':
            inputFirst = request.values.get('inputFirst')
            inputSecond = request.values.get('inputSecond')
            if inputFirst is None:
                inputFirst = "Not Submitted"
            if inputSecond is None:
                inputSecond = "Not Submitted"
            return "firstInput: "+inputFirst+' '+ "secondInput: "+inputSecond
        else:
            return render_template('test.html')
    

    To note, I have disabled the normal form submit and handled it using js. This means your form validation will not work. You can include the validation in the js. For now, I have just check if the value submitted is None in the view.

    I have created a div that is replaced by your submitted values on button click. Since you may have several divs(I only have one in that code), you may want to give the div an id so it does not replace all your divs

    Hope that will be useful

    I have put the form method as post, incase you get the submitted values in url with a refresh, you might have omitted that and your code doing the default get method