I am teaching myself CGI with python and I am having trouble finding any references on how to just insert the output of the python program into my current html instead of replacing the whole existing page.
Here is the python:
#!python
import cgi, cgitb
cgitb.enable()
form = cgi.FieldStorage()
def loan(r, term, pv):
if r is not None:
r = float(r)
if term is not None:
term = float(term)
if pv is not None:
pv = float(pv)
rate = r / 12
numPeriods = 12 * term
rate /= 100
monthlyPayment = (pv * rate) / (1 - (1 + rate) ** (numPeriods * -1))
return round(monthlyPayment, 2)
def getInput():
r = form.getvalue("rate")
term = form.getvalue("term")
pv = form.getvalue ("amount")
monthlyPayment = loan(r, term, pv)
print("<p>Monthly Payment: %.2f<p>" % monthlyPayment)
print "Content-type: text/html\r\n\r\n"
print """
<div>
<h1> Python CGI </h1>
<br />
"""
getInput()
print """
<br />
</div>
"""
And the HTML:
<DOCTYPE html>
<html>
<head>
<title> Python CGI Test </title>
</head>
<body>
<h1> Mortage Loan Calculator CGI</h1>
<form action ="/cgi-bin/myPython.py" method ="get">
Rate: <input type = "text" name = "rate"/> <br />
Term: <input type = "text" name = "term"/> <br />
Amount <input type = "text" name = "amount"/> <br />
<button type = "submit" > submit </button>
</form>
</body>
</html>
I would like the html from the python script to insert just below the form.
This is Server Side which means once the page is loaded, the only ways to reload content from Python is through reloading or AJAX. All the code will be run before the content is sent back to the user.
Related
I'm trying to automate a process where I take a snapshot everyday but change the filename to that date. For example, I'd like to reference today's file as "20200219 snapshot.png" and change it to "20200220 snapshot.png" tomorrow. The problem is, I can't input the variable name filename after the img src and have to put in the hardcoded exact String.
date = date.strftime('%Y%m%d')
filename = date + " snapshot.png"
html = """\
<html>
<head></head>
<body>
<img src="Directory/snapshot.png"/>
</body>
</html>
"""
You can use ElementTree to parse through the HTML DOM, use the find method to search for img tag. Then you can assign the src attribute value. The attributes are returned as a dict with the attrib parameter and you just need to look for the 'src' key:
import datetime
date = datetime.datetime.now().strftime('%Y%m%d')
filename = date + " snapshot.png"
import xml.etree.ElementTree as et
html = """\
<html>
<head></head>
<body>
<img src="Directory/snapshot.png"/>
</body>
</html>
"""
tree = et.fromstring(html)
image_attributes = tree.find('body/img').attrib
for k in image_attributes.keys():
if 'src' in k:
image_attributes[k] = filename
html_new = et.tostring(tree)
print(html_new)
Output:
b'<html>\n <head />\n <body>\n <img src="20200220 snapshot.png" />\n </body>\n</html>'
To pretty print this output, you can use the method provided in official docs here and just do:
et.dump(tree)
Output:
<html>
<head />
<body>
<img src="20200220 snapshot.png" />
</body>
</html>
Just make it a string preceded by f and add your variable between {} to the string
import datetime
date = datetime.datetime.now().strftime('%Y%m%d')
filename = date + " snapshot.png"
html = f"""\
<html>
<head></head>
<body>
<img src="Directory/{filename}"/>
</body>
</html>
"""
print(html)
Or use simple string concatenation instead
import datetime
date = datetime.datetime.now().strftime('%Y%m%d')
filename = date + " snapshot.png"
html = f"""\
<html>
<head></head>
<body>
<img src="Directory/"""
html += filename
html += """/>
</body>
</html>
"""
print(html)
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})
I have very simple code - Im looking for better solution my case:
I have:
- 2 input text + submit button
Input forms always returns text as string.
Do you know better solution (and shorter) to pass only numeric values (and for non numeric - show "error") except gather all letters in list and check statement if text from input is not in list with letters?
from flask import Flask, render_template, request
app = Flask(__name__)
#app.route("/licz/", methods=['GET'])
def search():
licz1 = request.args.get('liczba1')
licz2 = request.args.get('liczba2')
notnumbers = ['q','w','e','r','t','y']
if licz1 and licz2 != None:
if licz1 not in notnumbers:
sumaliczenia = int(licz1) + int(licz2)
return render_template('liczenie.html', suma=sumaliczenia)
else:
sumaliczenia = "error"
return render_template('liczenie.html', suma=sumaliczenia)
else:
return render_template('liczenie.html')
app.run(debug=True)
Template code (from comment below):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Formularz</title>
</head>
<body> Result is {{ suma }}
<form action="/licz/" method="get">
<input type="text" name="liczba1">
<input type="text" name="liczba2"> <button type="submit">Send</button>
</form>
</body>
</html>
You could just try to cast your inputs to int. If there is no numeric value in it Python will raise a ValueError, which you can catch and do the error stuff.
try:
input1 = int(input1)
input2 = int(input2)
except ValueError as e:
# print error
else:
# valid
sum = input1 + input2
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.
If the post function finds an error, I want it to communicate with the Get function so I can add the error to the main page.
How can this be done without templates?
Here is the code and also here is the solution video to the problem:
https://classroom.udacity.com/courses/cs253/lessons/48756009/concepts/485326480923#
import re
import cgi
import webapp2
# html boilerplate for the top of every page
page_header = """
<!DOCTYPE html>
<html>
<head>
<title>User-Signup</title>
</head>
<body>
<h1>Signup</h1>
"""
# html boilerplate for the bottom of every page
page_footer = """
</body>
</html>
"""
USER_RE = re.compile(r"^[a-zA-Z0-9_-]{3,20}$")
def valid_username(username):
return username and USER_RE.match(username)
PASS_RE = re.compile(r'^[\S]+#[\S]+\.[\S]+$')
def valid_password(password):
return password and PASS_RE.match(password)
EMAIL_RE = re.compile(r'^[\S]+#[\S]+\.[\S]+$')
def valid_email(email):
return not email or EMAIL_RE.match(email)
class MainHandler(webapp2.RequestHandler):
def get(self):
add_username = """
<form action="/" method="post">
<label>
Username <input type="text" name="user_name" value = ""/>
</label>
</form>
"""
add_password = """
<form action="/" method="post">
<label>
Password <input type="password" name ="password" value = ""/>
</label>
</form>
"""
validate_password = """
<form action="/" method="post">
<label>
Password <input type="password" name ="password" value = ""/>
</label>
</form>
"""
# error = self.request.get("error")
# if error:
# error_esc = cgi.escape(error, quote=True)
# error_element = '<p class="error">' + error_esc + '</p>'
# else:
error_element = ''
password_error = ''
content = page_header + add_username + error_element + add_password + password_error + page_footer
self.response.write(content)
def post(self):
error_element = ''
have_error = False
user_name = self.request.get("user_name")
password = self.request.get("password")
params = dict("")
if not valid_username(user_name):
error_element = "thats not a valid username"
have_error = True
if not valid_password(password):
password_error = "thats not a valid password"
have_error = True
add_username = """
<form method="post">
<label>
Username <input type="text" name="user_name" value = "{0}"/>
</label>
</form>
""".format(user_name)
add_password = """
<form method="post">
<label>
Password <input type="password" name ="password" value = "{0}"/>
</label>
</form>
""".format(password)
validate_password = """
<form action="/" method="post">
<label>
Password <input type="password" name ="password" value = "{0}"/>
</label>
</form>
""".format(password_error)
content = page_header + add_username + error_element + add_password + password_error + page_footer
self.response.write(content)
Basically I need to be able to reference a variable from the Post function in the Get function. I am not allowed to use templates.
What I have tried:
I tried using a redirect with an error.. However this doesnt seem to be the way its done in the video.
Please help me.
That video you linked is behind a login page, but it sounds like you want to redirect to the url for MainHandler.get(), and encode the error or error code as a request parameter on the url. That would look like this:
# in your post():
def post(self):
# your code here...
if have_error:
self.redirect(url + '?error=Your_Error_Here')
else:
self.response.write(content)
# in your get():
def get(self):
error = self.request.get('error', None)
if error is not None:
# handle your error here
else:
# no error to handle
You normally have two options when you want an http POST handler to forward information to an http GET handler:
As shown above, redirect to the appropriate url with the information encoded on the url (that is the ?error=Your_Error_Here part). I have often seen that used for error alerts and also confirmation messages if a form is posted successfully (think green checkmark on the screen after you hit "save")
Instead of sending the response from the post handler, you could actually call the get() handler from the post handler and respond with whatever response object comes out of that. In general, I would not recommend that.