Unable to pass data to a third form using Flask - python

I am able to pass data from one html form to a second html page using Flask. But when I try to pass the data from the second html page to a third html page, i get an error:
werkzeug.exceptions.BadRequestKeyError: 400 Bad Request: The browser (or proxy) sent a request that this server could not understand.
KeyError: 'binary'
I am basically trying to input binary numbers on the first html page, convert it to a decimal on the second html page, and then convert it to a hexadecimal number on the third page. Here is my Flask code:
from flask import Flask, redirect, url_for, render_template, request
app = Flask(__name__)
#app.route('/', methods=['POST','GET'])
def input_binary():
if request.method == "POST":
binary = request.form["binary"]
return redirect(url_for("show_decimal", bin=binary))
else:
return render_template("binary.html")
#app.route('/<bin>', methods=['POST','GET'])
def show_decimal(bin):
if request.method == "POST":
decimal = request.form["decimal"]
return redirect(url_for("show_hex", dec = decimal))
else:
decimal = int(bin,2)
return render_template("decimal.html", dec=decimal)
#app.route('/<dec>', methods=['POST','GET'])
def show_hex(dec):
hexadecimal_string = hex(int(dec))
return render_template("hex.html", hex = hexadecimal_string)
if __name__ == "__main__":
app.run(debug=True)
It seems like when i click submit on the second page again, it's trying to run the code from the def input_binary function and not the def show_hex function. Maybe it has to do with the submit button on the second page?
This is the html on the second html page:
<body>
<p>{{dec}}</p>
<form name="decimalNumber" action="." method="POST">
<label>Input the decimal number</label>
<input type="number" name="decimal">
<input type="submit" value="submit">
</form>
</body>
Any suggestions?

first, your input name "binary" may be conflicted with http protected keyname. try another name. you can see What is the cause of the Bad Request Error when submitting form in Flask application?

Related

How do I make an HTML button execute python code onclick?

I’m new to web development. I have learned how to make a web sever using flask. What I want to do is make an html button run python code from the web server when it is clicked. Is this even possible? If so, can someone point me to some html examples that can do that?
Update: I think I found some code that might work with what I’m asking. I don’t know for sure if it would work or not.
Here is the link:
Call a python function within a html file
If I were to convert the “click a link” aspect of the code to “click a button” would it run my python code on the viewers end, not my end?
It is Possible in Two ways
Create an HTML form and button to submit the form. The from can call the post URL on the flask server
Add some javascript to the HTML and call any HTTP method /url that you have created using the flask server.
You can use button with form or with JavaScript
Form
Normally to use button you need <form> which sends request to Flask to url defined in action="..." and Flask sends back response (text/HTML) and browser automatically put it in window in place of previous HTML - so server has to generate full HTML again and again.
from flask import Flask, request, render_template_string
import datetime
app = Flask(__name__)
#app.route('/')
def index():
return render_template_string('''<form action="/page" method="POST">
<button type="submit" name="btn" value="Button 1">Button 1</button>
<button type="submit" name="btn" value="Button 2">Button 2</button>
<button type="submit" name="btn" value="Button 3">Button 3</button>
</form>''')
#app.route('/page', methods=['GET', 'POST'])
def page():
value = request.form.get('btn') # gives text from `value="Button 1"`
return f'You pressed {value} at ' + datetime.datetime.now().strftime('%Y.%m.%d %H:%M.%S')
if __name__ == '__main__':
#app.debug = True
app.run() #debug=True
And the same using empty action="" so it sends request to the same url and it needs to check request.method to run different code
from flask import Flask, request, render_template_string
import datetime
app = Flask(__name__)
#app.route('/', methods=['GET', 'POST'])
def index():
if request.method == 'POST':
value = request.form.get('btn') # gives text from `value="Button 1"`
info = f'You pressed {value} at ' + datetime.datetime.now().strftime('%Y.%m.%d %H:%M.%S')
else:
info = ""
return render_template_string('''<form action="" method="POST">
<button type="submit" name="btn" value="Button 1">Button 1</button>
<button type="submit" name="btn" value="Button 2">Button 2</button>
<button type="submit" name="btn" value="Button 3">Button 3</button>
</form>{{text}}''', text=info)
if __name__ == '__main__':
#app.debug = True
app.run() #debug=True
JavaScript
If you want to execute Flask code without reloading all HTML then you need to use JavaScript which can send request to server using old
XMLHttpRequest or modern fetch(), get response and replace only part of HTML. Often in this method server sends JSON data and JavaScript may use it to replace HTML in different places.
And this method need to learn JavaScript to create something more complex.
from flask import Flask, request, render_template_string
import datetime
app = Flask(__name__)
#app.route('/')
def index():
return render_template_string('''
<button onclick="my_function()">Get Time</button>
<span id="time">Press Button to see current time on server.</span>
<script>
span_time = document.querySelector("#time");
function my_function(){
fetch('/get_time')
.then(res => res.text())
.then(text => span_time.innerHTML = text);
}
</script>
''')
#app.route('/get_time')
def time():
return datetime.datetime.now().strftime('%Y.%m.%d %H:%M.%S')
if __name__ == '__main__':
#app.debug = True
app.run() #debug=True
In examples I use render_template_string instead of render_template to make code simpler - now everyone can copy code and paste to one file and run it.

Internal server error when clicking button in flask app

I'm new to Flask and trying to build my first simple app which takes a text input and upon the user clicking a button I want it to display the text that was entered.
My HTML page loads successfully and I can enter the text into the input.
However, when I click the button I get a new page showing the following error:
Internal Server Error
The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.
My HTML:
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<h1>Predict Code</h1>
<form action="http://localhost:5000/predict" method="post">
<label form="description">Description:</label>
<input type="text" id="description" name="description">
<button type="submit">Predict Code</button>
</form>
<br>
<br>
{{ prediction_text }}
</body>
</html>
My flask app .py:
from flask import Flask, request, jsonify, render_template
# create the flask app
app = Flask(__name__)
# what html should be loaded as the home page when the app loads?
#app.route('/')
def home():
return render_template('app_frontend.html')
# define the logic for reading the inputs from the WEB PAGE,
# running the model, and displaying the prediction
#app.route('/predict', methods=['GET','POST'])
def predict():
# get the description submitted on the web page
a_description = request.form.values()
return render_template('Description entered: {}'.format(a_description))
# boilerplate flask app code
if __name__ == "__main__":
app.run(debug=True)
What have I done wrong and how can I fix it?
The problem is here:
#app.route('/predict', methods=['GET','POST'])
def predict():
# get the description submitted on the web page
a_description = request.form.values()
# THIS LINE:
return render_template('Description entered: {}'.format(a_description))
You're trying to render a template, but passing in a string, not a template.
If you want to return just the string, do this:
return 'Description entered: {}'.format(a_description)
If you look at the python error output you will see:
jinja2.exceptions.TemplateNotFound: Description entered: <generator
object MultiDict.values at 0x000001CEEEF83620>
EDIT
To answer the additional comment question. To get the value of the form post you will need to change your line from:
a_description = request.form.values()
to:
a_description = request.form.get('description')

Having trouble sending data from html to python using flask

I have an HTML index page that sends input data to a python script which processes the data and outputs it in a 2nd HTML page. On a local host, the process works fine and the data is displayed as desired. But when I try to host the process online, I get an error saying the URL cannot be found. If it helps, I'm using Heroku.
Apologies in advance for any poor lingo. I only just started learning how to code recently.
1st HTML
<form action = "https://webaddress/result" method = "POST">
<h1> Enter info: </h1>
<input type="text" name="info">
<input type="submit" value="Submit"/>
</form>
Python:
from flask import Flask, render_template, request
from bs4 import BeautifulSoup
import requests
# https://doi.org/10.2118/21513-MS
app = Flask(__name__)
#app.route('/')
def student():
return render_template('Trial.html')
#app.route('/result.html',methods = ['POST', 'GET'])
def result():
return render_template("result.html",result = output)
if __name__ == '__main__':
app.run(debug = True)
The input in the 1st HTML would be sent to the python section to be broken down and rearranged (left out that part so the python code wouldn't be too long) before being output into result.html. This worked on a local host using http://localhost:5000/ and http://localhost:5000/result.
When I run it on Heroku, I get the error message:
Not Found
The requested URL /result was not found on this server.
Update: Problem solved.
Having some issues understanding your results() function. output isn't defined anywhere and type isn't used at all.
I believe your action parameter is incorrect.
Try:<form action="/result" method = "POST">
Here is a working version of what I hacked together for you:
from flask import Flask, render_template, request
app = Flask(__name__)
#app.route('/', methods=['GET'])
def home():
return '''
<form action="/result" method = "POST">
<h1> Enter info: </h1>
<input type="text" name="info">
<input type="submit" value="Submit"/>
</form>
'''
#app.route('/result',methods = ['POST', 'GET'])
def result():
if request.method == 'POST':
type = ''
if 'info' in request.form:
result = request.form['info']
return result
if __name__ == '__main__':
app.run(debug=True, port=8888, host='0.0.0.0')
Your form refers to /result (no .html extension), but your route is for /result.html (with the extension). Try removing the .html from your route:
#app.route('/result', methods=['POST', 'GET'])
def result():
return render_template("result.html", result=output)

Use flask to receive data from form

I am trying to use flask to get data from a html form. The form shows up on the website ok, but when I submit python doesn't receive it.
Html code:
<form action="/signup" method="post">
<input type="text" name="email"></input>
<input type="submit" value="signup"></input>
</form>
Python code:
from flask import Flask, render_template, request, redirect
app = Flask(__name__)
#app.route('/')
def home():
return render_template('home.html')
#app.route('/about/')
def about():
return render_template('about.html')
#app.route('/signup', methods = ['POST'])
def signup():
email = request.form['email']
print("The email address is '" + email + "'")
return redirect('/')
if __name__ == '__main__':
app.run(debug=True)
APP
--static
----main.css
--templates
----html code(home.html)
python code(hello.py)
The code works fine for me.
The only thing I would change is using the url_for() construct instead of directly specifying your endpoints.
I.E.: use return redirect(url_for('home'))
Alternatively, try to provide a GET request for your 'signup' endpoint.
Add 'GET' to your methods argument
Put your printing block under an if statement (if request.method == "POST")
Underneath this block put something to return. (return redirect(url_for('home')), return render_template('xyz.html'), etc.)

Problems redirecting to dynamic URLs in Flask with 'action'

My app has a text box and a submission button. I am trying to create and redirect to dynamic URLs in my app, that are based off of what is typed in the text box. For example, the user enters in '1234', clicks submit, then is taken to 'website.com/results/1234'. The problem seems to be that the HTML for my button doesn't want to redirect the user to the new, dynamic URL. I am passing this to the HTML with Jinja.
Here is what I have.
The user starts on the home page, that is defined like this
#app.route("/home/", methods=["GET", "POST"])
def start():
return render_template("dashboard.html")
Dashboard.html has a text box and submission button (below). As you can see, the action of this button is to redirect to {{ results_page }}, where "results_page" comes from my Python function load_results (also below) and is passed to the HTML with render_template.
<div>
<form action="{{ results_page }}" class="form-inline" method="post">
<div class="form-group">
<label for="PubmedID">Pubmed ID(s)</label>
<input type="text" class="form-control" id="PubmedID" placeholder="18952863, 18269575" name="pmid" value="{{request.form.pmid}}">
</div>
<button type="submit" id= "myButton" class="btn btn-default" data-toggle="modal" data-target="#myModal">Submit</button>
</form>
</div>
The results page of my app uses the user input to look up some information and display it.
#app.route('/results/<query>', methods=["GET", "POST"])
def load_results(query):
form = pmidForm(secret_key='super secret key')
try:
if request.method == 'POST':
query = form.pmid.data #This is the user input
results_page = "website.com/results/"+query
return(query)
#do lots of stuff using the query
return render_template('results.html', form=form, results_page = results_page)
except Exception as e:
return(str(e))
If I run my app like this, the home page is fine, but when I click "Submit", the app doesn't take in the user input or do anything with it. Simply the home page refreshes.
I am new to web development, but since this code works fine if I hardcode the button to action = "website.com/results" in the HTML, AND do without the <query> in /results/<query> for the results page, I think that only a few adjustments should be needed to make my app dynamically redirect to and load pages correctly. Right now, I'm not sure what I'm missing. Please let me know where I'm going stray.
EDIT -
Now I have implemented a handle_form function that redirects to my dynamic URL. This function properly redirects but then I get a 404 error.
#app.route('/form/', methods=["POST"]) #handles form submission
def handle_form():
form = pmidForm(secret_key='super secret key')
if request.method == "POST":
query = request.form['pmid']
return redirect('/results/'+query)
I have also edited my form in the HTML action to go to /form/
<form action="website.com/form/" class="form-inline" method="post">
<div class="form-group">
<label for="PubmedID">Pubmed ID(s)</label>
<input type="text" class="form-control" id="PubmedID" placeholder="18952863, 18269575" name="pmid" value="{{request.form.pmid}}">
</div>
<button type="submit" id= "myButton" class="btn btn-default" data-toggle="modal" data-target="#myModal">Submit</button>
</form>
With this, my site will properly redirect to /results/<query>/ (e.g. /results/1234) but I get a 404 error. Here is how I have changed my load_results
#app.route('/results/<query>', methods=["GET"])
def load_results(query):
form = pmidForm(secret_key='super secret key')
try:
if request.method == 'GET':
query = form.pmid.data #THIS IS THE USER INPUT FROM THE FORM #referencing 'class pmidForm'
return query
.
.
#do stuff
I think I am very close but need to figure out why I am getting a 404 error. My guess is that I am using "GET" incorrectly. My form in the HTML uses method="post". Since this does not match with "GET", is there no way for my load_results(query) function to retrieve the contents of the form?
EDIT 2 -
Changed handle_form to redirect with url_for:
#app.route('/form/', methods=["POST"]) #handles form submission
def handle_form():
form = pmidForm(secret_key='super secret key')
if request.method == "POST":
query = request.form['pmid']
return redirect(url_for('.load_results', query=query))
And changed load_results to not return "query"
#app.route('/results/<query>', methods=["GET"])
def load_results(query):
form = pmidForm(secret_key='super secret key')
try:
if request.method == 'GET':
query = form.pmid.data # This shouldn't work??
.
.
# do stuff with the variable "query"
With this, it's still returning the 404 Error as before. Should I not be using if request.method == GET ?
Edit 3 -
Even a very simplified load_results will give me the 404 error, so I'm not sure what's up.
#app.route('/results/<query>', methods=["GET", "POST"])
def load_results(query):
q = query
return render_template('test.html', q=q)
EDIT - 3
It seems that the accepted solution IS the correct solution to this problem, however there is an issue with uwsgi in my server that is re-directing it to the wrong location :(
Your punctual problem is that /home route function also needs to put the results_page url on the templating context.
results_page = "website.com/results"
return render_template("dashboard.html", results_page=results_page)
Since the variable is undefined, flask is calling the original endpoint on the form submission.
Your larger problem is that your appraoch isn't going to get you a dynamic results url that looks like /results/1234.
Typical approaches are to redirect on the server side when you handle the post request; or to use JavaScript in the client to get the form data and change the browser location to /results/1234.
A simplified version of how to handle this with a server side redirect might look something like this. One route that handles the form submission and another that displays results. You simply redirect from one to the other to get the nice url.
#app.route('/form', methods=["POST"])
def handle_form():
query = form.pmid.data #This is the user input
return redirect(url_for('.load_results', query=query))
#app.route('/results/<query>') *removed the method spec to handle the redirect?
def load_results(query):
.
.
# do something with query

Categories

Resources