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.
Related
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("&", "&")
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">
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
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.
As you can see, this code lets the user create models called Images. The problem is, no images are actually created when I want them to be. The print test with the obnoxious caps (print images) returns an empty list after I've inputted information multiple times.
Perhaps related to this issue, I simply cannot add print tests to any of the if/else loops in the code. It returns an indentation error, even when I check all of the indents for four spaces.
I'm really confused. I suspect I'm misunderstanding the control flow?
views.py:
from django.shortcuts import render
from images_app.models import Image
def index(request):
images = Image.objects.all()
image_names = [a.name for a in images]
print images ### THIS RETURNS AN EMPTY LIST!!
if request.method == 'POST':
image_string = request.POST.get('get_image')
index = image_string.find('(')
# divide input into parent and child
if index == -1:
parent = image_string
child = None
else:
parent = image_string[0:index]
child = image_string[index+1:len(image_string)-1]
# print "Child is.. ", child.name ### THIS RETURNS AN INDENTATION ERROR
# create models based on input
if parent not in image_names and child not in image_names:
parent_model = Image(name=parent)
child_model = Image(name=child, parent=parent_model)
elif parent in image_names and child not in image_names:
parent_model = images.get(name=parent)
child_model = Image(name=child, parent=parent_model)
elif parent not in image_names and child in image_names:
child_model = images.get(name=child)
parent_model = Image(name=parent)
child_model.parent = parent_model
print "descendants are: ", parent_model.get_descendants()
else:
print "else"
return render(request, 'images_app/index.html', {'images':images})
def get_images(request):
term = request.GET.get('terms') #jquery-ui.autocomplete parameter
images = Image.objects.filter(name__istartswith=terms)
res = []
for i in images:
#make dict with the metadatas that jquery-ui.autocomple needs
dict = {'id':i.id, 'label':i.__unicode__(), 'value':i.__unicode__()}
res.append(dict)
return HttpResponse(simplejson.dumps(res))
index.html:
<!DOCTYPE html>
<html>
<head>
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script src="http://code.jquery.com/ui/1.10.3/jquery-ui.js"></script>
<title> images </title>
<script>
<script type="text/javascript">
$(function() {
$("#terms").autocomplete({
source: "{% url 'images_app:get_images' %}",
minLength: 1,
});
});
</script>
</head>
<nav>
associate
</nav>
<body>
{% for images in images %}
{{ image.name }}
{% endfor %}
<section>
<h1>create an image</h1>
<form action="{% url 'images_app:index' %}" method="post">
{% csrf_token %}
<div class="ui-widget">
<label for="get_image">create image: </label>
<input id="get_image" name="get_image">
</div>
<div id="buttons">
<input type="submit" value="create" class="submit" name="create" />
</div>
</form>
</section>
</body>
You don't ever save any of your images.
Doing Image(blah) simply instantiates an object in memory. You need to call .save() on the instance, or alternatively do Image.objects.create(blah) to instantiate and save at the same time.