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.html
file
<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.
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