Flask: how to update div after processing form inputs - python

My Flask app does calculations based on user form inputs. These calculation take about 10 seconds to complete. The output of those calculations need to be displayed in a div on the same page, next to the form (in a chart / table etc).
I have tried two aproaches. The first, using normal just Flask, reloads the whole page, which is far from ideal. The second approach, using Sijax, updates just the div. But in this case, i don't know how to access the form inputs.
I'm confused how to get this working. Would appreciate any directions!
Approach 1: just flask (downside: whole page reloads)
form_test.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Testpage</title>
</head>
<body>
<form action="{{ url_for('do_the_math') }}" method="post">
A = <input type="number" name="input_A">
B = <input type="number" name="input_B">
<input type="submit" value="Submit">
</form>
<div id="destination_div">A + B = {{ result }}</div>
</body>
</html>
app_normal.py:
from flask import Flask, render_template, request
app = Flask(__name__)
#app.route("/")
def show_home():
return render_template("form_test.html", result='unknown yet')
#app.route("/do_the_math", methods=['POST'])
def do_the_math():
A = request.form.get('input_A')
B = request.form.get('input_B')
sum = float(A) + float(B)
# reloads whole page
return render_template("form_test.html", result=sum)
# what i want: reload just update destination_div with new HTML
# return render_template("#destination_div", "A + B = " + str(sum))
if __name__ == '__main__':
app.run(debug=True)
Approach 2: use Sijax (updates div, but how to access form inputs?)
form_test_sijax.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Testpage with sijax</title>
<script type="text/javascript" src="/static/js/sijax/sijax.js"></script>
<script src='http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js'></script>
</head>
<body>
<form method="post">
A = <input type="number" name="input_A">
B = <input type="number" name="input_B">
<button type="button" onclick="Sijax.request('submit_form');">calc</button>
</form>
<div id="destination_div">A + B = unknown</div>
</body>
</html>
app_sijax.py
from flask import Flask, render_template, g
import flask_sijax
import os
app = Flask(__name__)
# init sijax
app.config["SIJAX_STATIC_PATH"] = os.path.join('.', os.path.dirname(__file__), 'static/js/sijax/')
app.config["SIJAX_JSON_URI"] = '/static/js/sijax/json2.js'
flask_sijax.Sijax(app)
def submit_form_handler(obj_response):
A = 5 # how do get to the values entered in the form?
B = 3
sum = A + B
obj_response.html("#destination_div", "A + B = " + str(sum))
#flask_sijax.route(app, "/")
def show_home():
result = 'unknown'
if g.sijax.is_sijax_request:
g.sijax.register_callback('submit_form', submit_form_handler)
return g.sijax.process_request()
return render_template("form_test_sijax.html")
if __name__ == '__main__':
app.run(debug=True)

You can use ajax with jquery to dynamically update the page with the computed result without having to refresh the page:
In the html file:
<html>
<header>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
</header>
<body>
<div class='wrapper'>
A = <input type="number" id="input_A">
B = <input type="number" id="input_B">
<button class='get_result'>Calculate</button>
<div class='result'></div>
</div>
</body>
<script>
$(document).ready(function(){
$('.wrapper').on('click', '.get_result', function(){
var val1 = $("#input_A").val();
var val2 = $("#input_B").val();
$.ajax({
url: "/calculate_result",
type: "get",
data: {val1: val1, val2:val2},
success: function(response) {
$(".result").html('<p>'+response.result.toString()+'</p>');
},
});
});
});
</script>
</html>
Then, in the main app file, create the route to calculate the final result:
#app.route('/calculate_result')
def calculate_result():
a = int(flask.request.args.get('val1'))
b = int(flask.request.args.get('val2'))
return flask.jsonify({"result":a+b})

Related

Flask go to new page on button click

I have a small flask app with an index page where the user selects a directory from a drop down menu. Once the user makes a selection and clicks "submit" on the webpage I would like to send them to a new page with info specific to that directory.
I'm trying to load the new page by simply calling the function after getting the input from the index page. My issue is that clicking submit on the webpage reloads the same index page.
Flask Code:
app = Flask(__name__)
dirname = os.path.dirname(sys.argv[0])
run_path = ""
#app.route("/", methods = ["GET", "POST"])
def index():
dir_loc = "/Users/kregan1/Documents"
dir_data = list(os.listdir(dir_loc))
if request.method == "POST":
run_dir = request.form.get("run_list")
run_path = dir_loc + "/" + run_dir
run(run_path)
return render_template('index.html', data = dir_data)
#app.route("/run", methods = ["GET", "POST"])
def run(run_path):
if os.path.isdir(run_path) == True:
file_lists = []
for f in os.listdir(run_path):
if f.startswith("pattern"):
file_lists.append(run_path + "/" + f)
projects = []
for fl in file_lists:
with open(fl) as f:
for row in f:
if row.split(",")[0] not in projects:
projects.append(row.split(",")[0])
else:
projects = ["a","b","c"]
return render_template('run.html', run = run_path, proj_data = projects )
index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='style.css') }}">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="{{url_for('static', filename='asp_javascript.js')}}"></script>
</head>
<body>
<h2>Packaging Tool - Index</h2>
<p>Select Run:</p>
<form action="{{ url_for("index") }}" method="post">
<select name="run_list">
{% for d in data %}
<option>{{d}}</option>
{% endfor %}
</select>
<br>
<input type="submit" value="submit">
</form>
</body>
</html>
You can use redirect(...) instead of just calling the function.
from flask import redirect
...
if request.method == "POST":
run_dir = request.form.get("run_list")
run_path = dir_loc + "/" + run_dir
return redirect(url_for('run', run_path=run_path))
#app.route("/run/<run_path>", methods = ["GET", "POST"])
def run(run_path):
if os.path.isdir(run_path) == True:
...

how to use ajax and flask return value?

How can I put the first value of the list in function make progress(i)? list is the value returned from flask!!
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Changing the Value of Bootstrap 4 Progress Bar Dynamically</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap#4.6.0/dist/css/bootstrap.min.css">
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap#4.6.0/dist/js/bootstrap.bundle.min.js"></script>
<style>
.bs-example{
margin: 20px;
}
</style>
</head>
<body>
<div class="bs-example">
<!-- Progress bar HTML -->
<div class="progress">
{{rist}}
<div class="progress-bar progress-bar-striped" style="min-width: 20px;"></div>
</div>
<form action="/list" method="POST">
<input type="hidden" name="ID" value="">
<input type="hidden" name="path" value="{{path}}">
</form>
<!-- jQuery Script -->
<script>
var i = rist;
function makeProgress(){
if(i < 100){
i = i + 1;
$(".progress-bar").css("width", i + "%").text(i + " %");
setTimeout("makeProgress()", 100);
}
// Wait for sometime before running this script again
else { document.forms[0].submit(); }
$.ajax({
type:'post',
async:'true',
url:'http://127.0.0.1:5000/ ',
data:{rist},
dataType: 'json',
success: function(data){rist
}
});
};
</script>
</div>
</body>
</html>
this is print(rist) // .py
list = [(h, e, dictionary[e]) for h, e in zip(category_name, category_id)]
x = []
for j in list:
x.append(j)
rist = str(100*(len(x) / len(list)))
print(rist)
1.1235955056179776
2.247191011235955
3.3707865168539324
4.49438202247191
5.617977528089887
6.741573033707865
7.865168539325842
8.98876404494382
10.112359550561797
11.235955056179774
12.359550561797752
13.48314606741573
14.606741573033707
15.730337078651685
16.853932584269664
17.97752808988764
19.101123595505616
20.224719101123593
21.34831460674157
22.47191011235955
23.595505617977526
24.719101123595504
25.842696629213485
26.96629213483146
28.08988764044944
29.213483146067414
30.337078651685395
31.46067415730337
32.58426966292135
33.70786516853933
34.831460674157306
35.95505617977528
37.07865168539326
38.20224719101123
39.325842696629216
40.44943820224719
41.57303370786517
42.69662921348314
43.82022471910113
44.9438202247191
46.06741573033708
47.19101123595505
48.31460674157304
49.43820224719101
50.56179775280899
51.68539325842697
52.80898876404494
53.93258426966292
55.0561797752809
56.17977528089888
57.30337078651685
58.42696629213483
59.55056179775281
60.67415730337079
61.79775280898876
62.92134831460674
64.04494382022472
65.1685393258427
66.29213483146067
67.41573033707866
68.53932584269663
69.66292134831461
70.78651685393258
71.91011235955057
73.03370786516854
74.15730337078652
75.28089887640449
76.40449438202246
77.52808988764045
78.65168539325843
79.7752808988764
80.89887640449437
82.02247191011236
83.14606741573034
84.26966292134831
85.39325842696628
86.51685393258427
87.64044943820225
88.76404494382022
89.8876404494382
91.01123595505618
92.13483146067416
93.25842696629213
94.3820224719101
95.50561797752809
96.62921348314607
97.75280898876404
98.87640449438202
100.0
and it is my flask code
from flask import Flask, render_template, request
from maratang import search
app = Flask(__name__)
#app.route('/')
def test():
return render_template('post.html')
#app.route('/progress', methods=['POST', 'GET'])
def loding():
global result, path, list, error
if request.method == 'POST':
result = request.form
path = request.form['path']
list, error, rist = search(path)
return render_template('progress.html', rist = rist)
#app.route('/list', methods=['POST'])
def post():
if request.method == 'POST':
print(list)
return render_template("result.html", result = result, list = list, error = error)
if __name__ == '__main__':
app.run()
I thought it was right, but there was an error, so I don't know what to do.

Python Forex Calculator Not Complying

I'm trying to complete a forex money converter in FLASK but my code isn't working.
It allows the user input, then once I hit submit the next page that shows Method Not Allowed
The method is not allowed for the requested URL.
-Update, now it just goes to an action page, whenever I try to pull up the Index2.html it doesn't load. I'm not sure why its not allowing me to proceed.
-I'm trying to save three inputs, add them to a list, then convert them into a dollar amount
-Page Refreshes to action page, this is not what is intended
Index.html file
><!DOCTYPE html>
<html>
<body>
<h2>HTML Forms</h2>
<form action="/index2.html", method="Post">
<label for="C1" name= "C1"> Converting From:</label><br>
<input type="text" id="C1" name="C1"><br>
<label for="C2">Converting To:</label><br>
<input type="text" id="C2_to" name="C2_to"><br>
<label for="amt">Amount:</label><br>
<input type="text" id="amt" name="amt"><br>
<br>
<input type="submit" value="Submit">
</form>
app.py file
from flask import Flask, render_template,request, redirect, session
from forex_python.converter import CurrencyCodes, CurrencyRates
app = Flask(__name__)
app.config["secret key"]="yeah"
app.config['DEBUG_TB_INTERCEPT_REDIRECTS'] = False
responses_key= "responses"
#app.route("/")
def show_form():
return render_template("Index.html" )
#app.route("/index2")
def show_form2():
return render_template("index2.html" )
T= CurrencyRates()
#app.route("/Index2", methods=["POST"])
def save_answer():
line2 = request.data.get("C1", "C2", int("amt"))
responses = session[responses_key]
responses.append(line2)
responses = session[responses]
rate = T.convert(line2[0],line2[1],int(line2[2]))
return rate,render_template("/Index2.html", rate="response")
As index2.htlm is not shared, i created a simple 1 liner index2.html to show the conversion. PFB code:
app.py:
from flask import Flask, render_template, request, redirect, session, url_for
from forex_python.converter import CurrencyCodes, CurrencyRates
app = Flask(__name__)
app.config["secret key"] = "yeah"
app.config['DEBUG_TB_INTERCEPT_REDIRECTS'] = False
responses_key = "responses"
#app.route('/', methods = ['GET', 'POST'])
def index():
return render_template('Index.html')
T = CurrencyRates()
#app.route("/conversion", methods = ['GET', 'POST'])
def conversion():
if request.method == 'POST':
C1 = request.form.get('C1', None)
C2_to = request.form.get('C2_to', None)
amt = request.form.get('amt', None)
rate = T.convert(C1, C2_to, int(amt))
print(C1, C2_to, amt, rate)
details = {'C1': C1, 'C2_to': C2_to, 'amt': amt, 'rate': rate}
return render_template("Index2.html", details=details)
if __name__ == '__main__':
app.run(host='xx.xx.xx.xx', debug=True)
app.run(debug=True)
Index.html:
<!DOCTYPE html>
<html>
<body>
<h2>HTML Forms</h2>
<form action="{{ url_for('conversion') }}" method="post">
<label for="C1" name= "C1"> Converting From:</label><br>
<input type="text" id="C1" name="C1"><br>
<label for="C2_to" name= "C2_to">Converting To:</label><br>
<input type="text" id="C2_to" name="C2_to"><br>
<label for="amt">Amount:</label><br>
<input type="text" id="amt" name="amt"><br>
<br>
<input type="submit" value="Submit">
</form>
Index2.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
</head>
<body>
<p> Conversion of {{ details.amt }} {{ details.C1 }} to {{ details.C2_to }} is: {{ details.rate }}</p>
</body>
</html>
Output:
homepage:
conversion page:

Why is my form trying to submit to the wrong endpoint?

I have a python script and a mongoDB instance.
With flask I now want to list all the items of my database on a webpage and use a second webpage to trigger the script to add an other item.
But everytime I click "submit" on the "/add" page, I get a "Method not allowed" and I can see, that it tries to submit it to "/" instead of "/add" ..
script.py
from flask import Flask, render_template, request
import requests, json, sys, getopt, smtplib
from os import system, name
from pathlib import Path
from pymongo import MongoClient
client = MongoClient(port = 27017)
db = client.amazonProducts
allitems = []
allMyItems = []
for document in db.items.find():
allitems.append(document["name"])
def addItem():
for dbWishList in db.wishlist.find():
url = dbWishList["wishlist"]
items = json.loads(requests.get(url).text)
if items:
for item in items:
itemName = str(item["name"])
itemPrice = item["new-price"]
itemUrl = str(item['link'])
if itemPrice:
itemPrice = str(itemPrice[26: ])
itemPrice = str(itemPrice[: itemPrice.find("<")])
itemPriceF = str(itemPrice.replace(".", ""))
itemPriceF = str(itemPriceF.replace("€", ""))
itemPriceF = str(itemPriceF.replace("\xa0", ""))
itemPriceF = str(itemPriceF.replace(",", ".")).replace("\xf6", "")
itemPriceFi = float(itemPriceF)
itemUrl = itemUrl[: itemUrl.find("?coliid")]
itemNameF = itemName.replace('"', '"')
itemNameFi = itemNameF.replace("&amp;", "&")
itemNameFi = itemNameFi.replace("ü", "ue").replace("ö", "oe").replace("ä", "ae").replace(" ", " ").replace("–", "-")
amazonItem = {
'name': itemNameFi,
'url': itemUrl,
'price': itemPriceFi,
'maxPrice': 0
}
db.items.insert_one(amazonItem)
for document in db.items.find():
allMyItems.append(document["name"])
return allMyItems
app = Flask(__name__)
#app.route('/')
def homepage():
return render_template("index.html", len = len(allitems), allitems = allitems)
app.run(use_reloader = True, debug = True)
app.config["DEBUG"] = True
#app.route("/add", methods = ["GET", "POST"])
def secPage():
errors = ""
if request.method == "POST":
global testingVar
testingVar = None
try:
testingVar = string(request.form["testingVar"])
except:
errors += "<p>{!r} is not a string.</p>\n".format(request.form["testingVar"])
if testingVar is not None:
addItem()
return render_template("secIndex.html", len = len(allMyItems), allMyItems = allMyItems)
return '''
<html>
<body>
{errors}
<p>What you wanna do?:</p>
<form method="post" action=".">
<p><input name="testingVar" /></p>
<p><input type="submit" value="Do magic" /></p>
</form>
</body>
</html>
'''.format(errors=errors)
index.html
<!DOCTYPE html>
<html>
<head>
<title>For loop in Flask</title>
</head>
<body>
<ul>
<!-- For loop logic of jinja template -->
{%for i in range(0, len)%}
<li>{{allitems[i]}}</li>
{%endfor%}
</ul>
</body>
</html>
secIndex.html
<!DOCTYPE html>
<html>
<head>
<title>For loop in Flask</title>
</head>
<body>
<!-- For loop logic of jinja template -->
<form method="post" action=".">
<p><input name="testingVar" /></p>
<p><input type="submit" value="Do magic" /></p>
</form>
</body>
</html>
The items are built like:
amazonItem = {
'name': itemNameFi,
'url': itemUrl,
'price': itemPriceFi,
'maxPrice': 0
}
Can anyone here follow me and tell me where my mistake might be?
In your form definition you have:
<form method="post" action=".">
The action attribute needs to have the endpoint you want to send the post request to. In your case, you want
<form method="post" action="/add">
If you omit the action attribute, it will submit the post request to the current page, so if you are viewing your form from /add, you can just use
<form method="post">

How do I pass user input from html to python?

so I'm using bottle to connect my html and python code but I don't know how to take user input from my html code and use it as a variable in my python code. I have posted my code below, please help.
This is my bottle code
from bottle import default_app, route, template, post, request, get
#route('/')
def showForm():
return template("form.html")
#post('/response')
def showResponse():
return template("response.html")
application = default_app()
This is my main form which asks for the user input
<!DOCTYPE html>
<html lang = "en-us">
<head>
<title>BMI Calculator</title>
<meta charset = "utf-8">
<style type = "text/css">
body{
background-color: lightblue;
}
</style>
</head>
<body>
<h1>BMI Calculator</h1>
<h2>Enter your information</h2>
<form method = "post"
action = "response">
<fieldset>
<label>Height: </label>
<input type = "text"
name = "feet">
ft
<input type = "text"
name = "inches">
in
<br>
<label>Weight:</label>
<input type = "text"
name = "weight">
lbs
</fieldset>
<button type = "submit">
Submit
</button>
</form>
</body>
And this is my response code which displays a page when the user hits submit, I embedded my python code to be able to calculate the user's bmi
<%
weight = request.forms.get("weight")
feet = request.forms.get("feet")
inches = request.forms.get("inches")
height = (feet * 12) + int(inches)
bmi = (weight/(height^2)) * 703
if bmi < 18.5:
status = "underweight"
elif bmi < 24.9 and bmi > 18.51:
status = "normal"
elif bmi > 25 and bmi < 29.9:
status = "overweight"
else:
status = "obese"
%>
<!DOCTYPE html>
<html lang = "en-us">
<head>
<title>Calculation</title>
<meta charset = "utf-8">
</head>
<body>
<h1>Your Results</h1>
<fieldset>
<label>BMI : </label>
<input type = "text"
name = "BMI"
value = {{bmi}}>
<br>
<label>Status:</label>
<input type = "text"
name = "status"
value = {{status}}>
</fieldset>
</body>
It looks like you don't even attempt to access your form data in POST route. forms property of bottle.request object holds all parsed form data. Bottle documentation provides a good example on how to handle form data.
Also, it's really a bad idea to put logic into templates beyond what is needed for correct page rendering. You need to process data in your route or to move processing into a separate module for better separation of responsibilities.

Categories

Resources