How to send data in Flask to another page? - python

I'm using Flask to make a tickets booking app. But for now I'm little confused on how to send data from one page to another page, like this snippet of code:
#app.route('/index', methods = ['GET', 'POST'])
def index():
if request.method == 'GET':
date = request.form['date']
return redirect(url_for('main.booking', date=date))
return render_template('main/index.html')
#app.route('/booking')
def booking():
return render_template('main/booking.html')
The date variable is a request from a form, and for now I want to send the date data to booking function. What is term for that purpose..?

Passing data is possible for get request from one route to another.
You are almost there to get the submitted date value in booking route.
app.py:
from flask import Flask, render_template, request, jsonify, url_for, redirect
app = Flask(__name__)
#app.route('/', methods = ['GET', 'POST'])
def index():
if request.method == 'POST':
date = request.form.get('date')
return redirect(url_for('booking', date=date))
return render_template('main/index.html')
#app.route('/booking')
def booking():
date = request.args.get('date', None)
return render_template('main/booking.html', date=date)
if __name__ == '__main__':
app.run(debug=True)
main/index.html:
<html>
<head></head>
<body>
<h3>Home page</h3>
<form action="/" method="post">
<label for="date">Date: </label>
<input type="date" id="date" name="date">
<input type="submit" value="Submit">
</form>
</body>
</html>
main/booking.html:
<html>
<head></head>
<body>
<h3>Booking page</h3>
<p>
Seleted date: {{ date }}
</p>
</body>
</html>
Output:
Home route with a form to submit the date
Getting the date in booking route
Disadvantages:
The values (e.g.: date) are passed as URL parameters from one route to another.
Anyone with a get request can access the second part (e.g. booking route).
Alternatives:
Use session storage as #VillageMonkey suggested.
Use Ajax to facilitate multi part forms.

You can also use flask session to send data from one page to another page.
from flask import Flask, render_template, request, jsonify, url_for, redirect,
session
app = Flask(__name__)
#app.route('/', methods = ['GET', 'POST'])
def index():
if request.method == 'POST':
date = request.form.get('date')
session["date"] = date
return redirect(url_for('booking', date=date))
return render_template('main/index.html')
#app.route('/booking')
def booking():
date = session.get("date")
return render_template('main/booking.html', date=date)
if __name__ == '__main__':
app.run(debug=True)

Related

Problem with FLask Could not build url for endpoint 'success'. Did you forget to specify values ['name']?

I have been trying to solve this issue for some time. I have a simple flask python file that reads as follows:
from flask import Flask, redirect, url_for, request
app = Flask(__name__)
#app.route('/success/<name>')
def success(name):
return 'welcome %s' % name
#app.route('/login',methods = ['POST', 'GET'])
def login():
if request.method == 'POST':
user = request.form['nm']
return redirect(url_for('success',name = user))
else:
user = request.args.get('nm')
return redirect(url_for('success',name = user))
if __name__ == '__main__':
app.run(host="0.0.0.0")
and the login.html is
<html>
<body>
<form action = "http://localhost:5000/login" method = "post">
<p>Enter Name:</p>
<p><input type = "text" name = "nm" /></p>
<p><input type = "submit" value = "submit" /></p>
</form>
</body>
</html>
i write python gello.py at the terminal and go to browser to check the results.. I get the following message
werkzeug.routing.BuildError: Could not build url for endpoint 'success'.
Did you forget to specify values ['name']?
If you can help me, that would be great.

Flask HTTP Method Not Allowed Message

from flask import Flask, render_template,request
app = Flask(__name__)
#app.route('/',methods=['post'])
def main():
if (request.method=="POST"):
text=request.form('write')
if(text==None):
text=""
else:
text=""
return render_template('form.html',text=text)
if __name__ == "__main__":
app.run(debug=True)
I want to receive only POST method. So I set method option to methods=["post"]. But it always sends HTTP 405 Not Allowed Method error.
<html>
<head>
<title>Using Tag</title>
</head>
<body>
<form method="POST">
<input type="text" name="write">
<input type="submit">
</form>
{{ text }}
</body>
</html>
I want to know reason why this application only sends HTTP 405 response.
To access the HTML form from / path you need to enable both GET and POST request in that route. Otherwise when you try to access the root path / from your browser, you will get the HTTP Method not allowed error.
app.py:
from flask import Flask, render_template, request
app = Flask(__name__)
#app.route('/', methods=['POST', 'GET'])
def main():
text = ""
if request.method == "POST":
text = request.form['username']
return render_template('form.html', text=text)
if __name__ == "__main__":
app.run(debug=True)
templates/form.html:
<html>
<head>
<title>Using Tag</title>
</head>
<body>
<form method="POST">
<input type="text" name="write">
<input type="submit">
</form>
{{ text }}
</body>
</html>
Output:
Explanation (Updated):
To access the form value use request.form['INPUT_FIELD_NAME'].
We are making GET and POST requests to the / route. So, we set GET and POST requests in the methods options of the / route. When we are viewing the page using the browser, we make GET request to that page. When we submit the form, we make POST request to that page. In this case, we are storing the form value in the text variable and pass the value to the template. For GET request we are showing the empty text value.
The above snippet is the same as the following snippet:
from flask import Flask, render_template, request
app = Flask(__name__)
#app.route('/', methods=['POST', 'GET'])
def main():
if request.method == "POST":
text = request.form['username']
return render_template('form.html', text=text)
elif request.method == "GET":
return render_template('form.html', text="")
if __name__ == "__main__":
app.run(debug=True)
References:
Flask documentation for request object

Prevent duplicate form submissions while awaiting a response Flask Python

I am running a large request via API and massaging some data before the user sees it. I am looking to prevent the user from clicking the download button while all this information is processed. What would be the best way to accomplish this through a Flask Form?
Here is my HTML:
<form method="POST">
<button type="submit" name="download" value="download" class="button is-primary is-light">Download</button>
{% if error_statement %}
<article class="message is-danger">
<div class="message-body">
{{ error_statement }}
</div>
</article>
{% endif %}
</form>
Here is my Flask Form:
from datetime import date
import pandas as pd
from flask_wtf import FlaskForm
from wtforms import *
from flask import (
Flask,
g,
redirect,
render_template,
request,
session,
url_for,
flash,
Response
)
app = Flask(__name__)
app.secret_key = 'secret'
#app.route('/home', methods=["POST", "GET"])
def home():
class MyForm(FlaskForm):
submit = SubmitField('Download')
if request.method == 'POST':
form = MyForm()
if request.form['download'] == 'download':
#At this point I have code where I call a bunch of APIs and convert data to a CSV file
#This process takes anywhere between 1-3 minutes to complete
if not final_df.empty:
today = date.today()
return Response(final_df.to_csv(index=False, header=True), mimetype="text/csv", headers={"Content-disposition": "attachment; filename=export" + today.strftime("%Y/%m/%d") + ".csv"})
else:
error_statement = 'Something Went Wrong Please Try Again'
return render_template("login.html", error_statement=error_statement)
return render_template('home.html', form=form)
return redirect(url_for('login'))
Can anyone provide guidance on how to prevent the user from clicking the download button while my data is processed?

String POST Request to Flask

I'm trying to implement a simple dashboard with Flask that will:
Accept a user text input, with a "submit" button. POST this user input to flask.
Flask accepts this input, does some stuff to it, then makes a GET request to another API.
This GET request returns data and shows it somehow (can just be console.log for now)
As an example, with the star wars API:
User inputs name of a Star Wars character (assume no spelling errors)
Flask reads this input name, and maps it to an ID number, because the Star Wars API accepts id numbers. Form a GET request to the Star Wars API, to get full character information.
For now, we can just console.log character information (e.g. "height", "mass", etc.)
What I have now:
app.py
from flask import Flask, jsonify, request, render_template
import random
import json
app = Flask(__name__)
#app.route("/")
def index():
return render_template('index.html')
#app.route("/form_example", methods=["GET", "POST"])
def form_example():
if request.method == "POST":
language = request.form("character_name")
starwars_dictionary = {"Luke Skywalker":"1", "C-3PO":"2", "R2-D2": "3"}
# starwars_dictionary is a dictionary with character_name:character_number key-value pairs.
# GET URL is of the form https://swapi.co/api/people/<character_number>
return render_template("index.html")
if __name__ == "__main__":
app.run(debug=True)
index.html
<!DOCTYPE html>
<html>
<head>
<title>py-to-JS</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
</head>
<body>
<h3>Sample Inputs</h3>
<ul>
<li>Luke Skywalker</li>
<li>C-3PO</li>
<li>R2-D2</li>
</ul>
<form method="POST">
Enter Name: <input type="text" name="character_name"><br>
<input type="submit" value="Submit"><br>
</form>
</body>
</html>
In this current form, when I run the app, it returns "Method not allowed; this method is not allowed for the requested URL".
I'm not sure what I'm missing; it's probably just not wired together properly but I'm not sure what the proper syntax is.
Working version after implementing the accepted answer:
app.py
from flask import Flask, jsonify, request, render_template
import requests
import random
import json
app = Flask(__name__)
#app.route("/index", methods=["GET", "POST"])
def index():
#character_height = "" # init a default value of empty string...seems unwieldy
if request.method == "POST":
character_name = request.form.get("character_name")
# Map user input to a numbers
starwars_dictionary = {"Luke Skywalker":"1", "C-3PO":"2", "R2-D2": "3"}
char_id = starwars_dictionary[character_name]
url = "https://swapi.co/api/people/"+char_id
response = requests.get(url)
response_dict = json.loads(response.text)
character_height = response_dict["height"]
return render_template("index.html", character_height=character_height)
return render_template("index.html")
##app.route("/form_example", methods=["GET", "POST"])
#def form_example():
if __name__ == "__main__":
app.run(debug=True)
index.html
<!DOCTYPE html>
<html>
<head>
<title>py-to-JS</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
</head>
<body>
<h3>Sample Inputs</h3>
<ul>
<li>Luke Skywalker</li>
<li>C-3PO</li>
<li>R2-D2</li>
</ul>
<form method="POST" action="/index">
Enter Name: <input type="text" name="character_name"><br>
<input type="submit" value="Submit"><br>
</form>
{{ character_height }}
</body>
</html>
Probably the form is posting to the / endpoint, because you didn't declare a form action.
Needs to be more like:
<form method="POST" action="/form_example">
Or if you want to get snazzy and use Jinja's url_for function:
<form method="POST" action="{{ url_for('form_example') }}">
EDIT: That said, you could handle this with a single route function:
#app.route("/", methods=["GET", "POST"])
def index():
if request.method == "POST":
language = request.form("character_name")
starwars_dictionary = {"Luke Skywalker":"1", "C-3PO":"2", "R2-D2": "3"}
# Logic to query remote API ges here.
else: # Assume method is GET
return render_template("index.html")
Then make the form action {{ url_for('index') }}

How to return also json and render_template in Flask?

I've implemented a service in Python with Flask, to create the server. My service (MyService) take a query from the user and return a response, like a chatbot. So, i want to return both a text respons modifying the Html template, and a json containing response for using service as command line.
At the moment my service only return a render template,how I can do?
My app:
app = Flask(__name__)
#app.route("/")
def main():
return render_template('index.html')
#app.route("/result", methods=['POST', 'GET'])
def result():
if request.method == 'POST':
query = request.form['query']
response = MyService.retrieve_response(query)
return render_template("index.html", value=response)
if __name__ == "__main__":
app.run()
And my simple index.html:
<!DOCTYPE html>
<html lang="en">
<body>
<h2>Wellcome!</h2>
<form action="http://localhost:5000/result" method="POST">
Make a question:<br>
<br>
<input type="text" name="query" id="query">
<br><br>
<input type="submit" value="submit"/>
</form>
<br>
<h3>Response is: </h3>
<br>
{{value}}
</body>
</html>
You can branch out your return based on request type. If the request is for html text, return the render_template. If the request is for json, return json. For example:
#app.route("/result", methods=['POST', 'GET'])
def result():
if request.method == 'POST':
query = request.form['query']
response = MyService.retrieve_response(query)
if request.headers['Content-Type'] == 'application/json':
return jsonify(...)
return render_template("index.html", value=response)
#dvnguyen's answer is good, but you might consider creating different routes for html and for json. For example:
#app.route("/web/result")
def result_html():
response = MyService.retrieve_response()
return render_template("index.html", value=response)
#app.route("/api/result")
def result_json():
response = MyService.retrieve_response()
return jsonify(response)
The /api or /web prefix makes the intention clear, and also simplifies unit testing.

Categories

Resources