How to load dropdowns and pass values using flask - python

using Python and Flask I have this Flask file which should take a couple of inputs from the user and pass those to a python script to be used. I can get 2 boxes that will accept numbers as inputs and those work just fine using the code below.
from flask import Flask, request, render_template
import os
import csv
import fileinput
import codecs
import re
import pandas as pd
import os
from pandas.core.dtypes.missing import notnull
from races import calculate_mode
from races import do_calculation
#import races
app = Flask(__name__)
app.config["DEBUG"] = True
inputs = []
#app.route("/testing", methods=["GET", "POST"])
def testing():
errors = ""
number1 = None
number2 = None
colours = ['Red', 'Blue', 'Black', 'Orange']
if request.method == "POST":
try:
number1 = float(request.form["number1"])
except:
errors += "<p>{!r} is not a number.</p>\n".format(request.form["number1"])
try:
number2 = float(request.form["number2"])
except:
errors += "<p>{!r} is not a number.</p>\n".format(request.form["number2"])
if number1 is not None and number2 is not None:
result = do_calculation(number1, number2)
return '''
<html>
<body>
<p>The result is {result}</p>
<p>Click here to calculate again
</body>
</html>
'''.format(result=result)
return '''
<html>
<body>
{errors}
<p>Enter your numbers:</p>
<form method="post" action=".">
<p><input name="number1" /></p>
<p><input name="number2" /></p>
<p><input type="submit" value="Do calculation" /></p>
</form>
</body>
</html>
'''.format(errors=errors)
if __name__ == "__main__":
app.run(debug=True)
But for this application it really needs to be drop down boxes. I have gotten a dropdown box to load using something like this:
#app.route("/dropdown", methods=["GET", "POST"])
def select():
colours = ['Red', 'Blue', 'Black', 'Orange']
return render_template('select.html', colours=colours)
However I don't know how to pass arguments from a newly loaded page and the python file. So instead I'm trying to load the html in the same file by replacing the second 'return' with the code below (which is basically the same as the file that is loaded with select.html) but can't get the dropdown to work (error is KeyError: '% for colour in colours')
return '''
<html>
<form>
<select name="colour" method="POST" action="/">
<option value="{{colours[0]}}" selected>{{colours[0]}}</option>
{% for colour in colours[1:] %}
<option value="{{colour}}">{{colour}}</option>
{% endfor %}
</select>
<p><input type="submit" value="Do calculation" /></p>
</form>
</html>
'''.format(errors=errors)
Does anyone know why it won't work, or have a better idea of how to do this?

Your problem is that you use .format() to format HTML and format treats all { } as places for variables - even {%...%} - and it doesn't know what means this {% ... %}.
You should use render_template_string() instead of format()
if number1 is not None and number2 is not None:
result = do_calculation(number1, number2)
html = '''
<html>
<body>
<p>The result is {{ result }}</p>
<p>Click here to calculate again
</body>
</html>
'''
return render_template_string(html, result=result)
html = '''
<html>
<form>
{{ errors }}
<select name="colour" method="POST" action="/">
<option value="{{ colours[0] }}" selected>{{colours[0]}}</option>
{% for colour in colours[1:] %}
<option value="{{ colour }}">{{ colour }}</option>
{% endfor %}
</select>
<p><input type="submit" value="Do calculation" /></p>
</form>
</html>'''
return render_template_string(html, colours=colours, errors=errors)
or
if number1 is not None and number2 is not None:
result = do_calculation(number1, number2)
return render_template_string('''
<html>
<body>
<p>The result is {{ result }}</p>
<p>Click here to calculate again
</body>
</html>
''', result=result)
return render_template_string('''
<html>
<form>
{{ errors }}
<select name="colour" method="POST" action="/">
<option value="{{ colours[0] }}" selected>{{colours[0]}}</option>
{% for colour in colours[1:] %}
<option value="{{ colour }}">{{ colour }}</option>
{% endfor %}
</select>
<p><input type="submit" value="Do calculation" /></p>
</form>
</html>''', colours=colours, errors=errors)

Related

How can I find the data which written with for loop in Flask

I'm trying to make a database project using with MYSQL and I'm new in Flask. In this project, the user should be able to increase and decrease the number of the products in the database. I print the items in my product table with for loop. The problem is I couldn't select the item which the user selected.
Html:
{% for mydata in data %}
<div class="items filterDiv {{ mydata[1] }}">
<img src="../static/foto/atayumurta.png" alt="">
<br><br>
<label for="item"> {{ mydata[3] }}</label>
<br><br>
<label class="Number">Number: <input class="numb" min="1" name="number" type="number"></label>
<br><br>
<input class="addbutton" type="submit" name="submit_button" value="Add">
<input class="removebutton" type="submit" name="removebutton" value="Remove">
</div>
{% endfor %}
Flask:
#app.route('/mainpage', methods=['POST','GET'])
def mainpage():
cursor.execute("SELECT * FROM product")
fetchdata = cursor.fetchall()
if request.method == 'POST':
if request.form['submit_button'] == 'Add':
number = request.form.get("number")
print(number)
return render_template('main.html', data=fetchdata)
else:
return render_template('main.html', data = fetchdata)
First, I wanted to see the number that the user has selected. So tried to print it but it prints null. As I said im new in flask, open for your suggestions.
Actually, the template contains a for loop for data.
In other words, the number field is not unique. So you need to modify the code. For example
{% for i in range(len(data)) %}
<div class="items filterDiv {{ data[i][1] }}">
<img src="../static/foto/atayumurta.png" alt="">
<br><br>
<label for="item"> {{ data[i][3] }}</label>
<br><br>
<label class="Number">Number: <input class="numb" min="1" name="number{{i}}" type="number"></label>
<br><br>
<input class="addbutton" type="submit" name="submit_button" value="Add">
<input class="removebutton" type="submit" name="removebutton" value="Remove">
</div>
{% endfor %}
Flask:
#app.route('/mainpage', methods=['POST','GET'])
def mainpage():
cursor.execute("SELECT * FROM product")
fetchdata = cursor.fetchall()
if request.method == 'POST':
if request.form['submit_button'] == 'Add':
number = request.form.get("number1")
print(number1)
return render_template('main.html', data=fetchdata)
else:
return render_template('main.html', data = fetchdata)

How to get dynamic html table entries in a form to flask?

I am trying to create a form with an embedded table that the user can dynamically add and remove table rows while entering content into the cell inputs.
HTML
<form id="myForm" action="{{ url_for('hello_world') }}" method="POST">
<div class="form-row text-left">
<div class="col-1 text-left">
<input type="checkbox" id="skills" name="skills" value="Yes">
</div>
<div class = "col-11 text-left">
<h2>TECHNICAL SKILLS</h2>
</div>
</div><!--form-row-->
<div class="form-row">
<table id="myTable" name="skillsTable">
<tr>
<th>Category</th>
<th>Entries</th>
</tr>
</table>
</div><!--form-row-->
<br>
<button type="button" onclick="addSkill()">Add Row</button>
<button type="button" onclick="deleteSkill()">Delete row</button>
<hr>
<input type="submit" value="Submit" onclick="submit()" />
</form>
As you can see in the screenshot [![screenshot of the user form][1]][1] the name attribute is correctly being appended to added cell.
The goal is to have a way to get the table values dynamically created by the user over to the flask template where they can be displayed.
Javascript
<script>
var c1=0;
var c2=0;
function addSkill() {
var table = document.getElementById("myTable");
var row = table.insertRow(-1);
var cell1 = row.insertCell(0);
var cell2 = row.insertCell(1);
cell1.innerHTML = "<input type='text' value=' ' name=cell1_"+c1.toString()+"> ";
cell2.innerHTML = "<input type='text' value=' ' name=cell2_"+c2.toString()+"> ";
c1++;
c2++;
}
function deleteSkill() {
document.getElementById("myTable").deleteRow(-1);
}
</script>
I have tried setting the name attribute for each newly created cell using a counter, but this still does not show up rendered in the flask template:
flask
#app.route('/hello_world', methods=['GET', 'POST'])
def hello_world():
if request.method == 'POST':
result = {}
try:
skills = request.form['skills']
result['skills'] = skills
result['value'] = request.form['cell1_1']
except:
pass
return render_template("result.html",result = result)
result.html
{% if result.skills %}
<p>{{ result.value }}</p>
{% endif %}
In this example, I would expect to see "Language" show up on rendered after submitting the form if the checkbox is selected.
How can I refer to the table in the form from flask and loop through the <input> elements if they are dynamically created? Thx
[1]: https://i.stack.imgur.com/samhG.png
result.html
{% if result.skills %}
{% set skillsTable = result.skillsTable %}
<h2>TECHNICAL SKILLS</h2>
<table>
{% for skill in skillsTable %}
{% if loop.index|int % 2 == 0 %}
<tr><td>{{ skillsTable.pop(0) }}:</td><td>{{ skillsTable.pop(0) }}</td></tr>
{% else %}
<tr><td>{{ skillsTable.pop(0) }}:</td><td>{{ skillsTable.pop(0) }}</td></tr>
{% endif %}
{% endfor %}
{% endif %}
flask
#app.route('/hello_world', methods=['GET', 'POST'])
def hello_world():
if request.method == 'POST':
result = {}
try:
skills = request.form['skills']
result['skills'] = skills
result['skillsTable'] = []
form = request.form
for key, value in form.items():
if key.startswith("cell"):
result['skillsTable'].append(value)
except:
pass
return render_template("result.html",result = result)

Multiple buttons in html, same view, different values

I'm trying to have my html display a session.counter on an HTML page. The counter should increment by a random number, with 4 different options for the range at which it increments (based on buttons). So far, I have all their actions routing to the same view, but I'm not sure how to code the values into the view! Can I nest multiple if-checks into the view? If so, do I need to redirect immediately after each check, or can it be after the if-checks?
EDIT: I've tried adding hidden inputs to make my view more efficient. I'm still a novice, so if the more descriptive your feedback, the easier it will be for me to implement changes and understand why!
Here's the html:
<div id="goldCount">
<h2>Gold Count: {{ session.request.goldCount }}</h2>
</div>
<div id="goldNode">
<h2>Blood Lotus Master</h2>
<h5>(earns 50 to 200 gold coins)</h5>
<form action='/process_gold' method="post">
{% csrf_token %}
<input type="hidden" name="earn" value="reap">
<button type="submit" name="reap">収める - Reap</button>
</form>
</div>
<div id="goldNode">
<h2>Shadow Dance Troupe</h2>
<h5>(earns 35 to 50 gold coins)</h5>
<form action='/process_gold' method = "post">
{% csrf_token %}
<input type="hidden" name="earn" value="weave">
<button type = "submit" name = "weave">織る - Weave</button>
</form>
</div>
<div id="goldNode">
<h2>Necromancy</h2>
<h5>(earns -200 to 200 gold coins)</h5>
<form action='/process_gold' method="post">
{% csrf_token %}
<input type="hidden" name="earn" value="summon">
<button type = "submit" name="summon">召喚 - Summon</button>
</form>
</div>
<div id="goldNode">
<h2>Clan War!</h2>
<h5>(earns -2000 to 2000 gold coins)</h5>
<form action='/process_gold' method="post">
{% csrf_token %}
<input type="hidden" name="earn" value="summon">
<button type="submit" name="war">影の戦争 - Shadow War</button>
</form>
</div>
and here is the views.py file
def index(request):
if 'goldCount' not in request.session:
request.session['goldCount'] = 0
return render(request, 'index.html')
def process_gold(request):
reap = random.randint(50,200)
weave = random.randint(35,50)
summon = random.randint(-200,200)
war = random.randint(-2000,2000)
print(request.POST)
if request.POST['earn'] == 'reap':
request.session['goldCount'] += random.randint(50,200)
if request.POST['earn'] == 'weave':
request.session['goldCount'] += random.randint(35,50)
if request.POST['earn'] == 'summon':
request.session['goldCount'] += random.randint(-200,200)
if request.POST['earn'] == 'war':
request.session['goldCount'] += random.randint(-2000,2000)
return redirect('/')
If you want to send goldCount through to HTML you need to use a render_template rather than a redirect. Store the goldCount into session then just call {{request.session.goldCount}} in your HTML.
Also, the correct if statement would be:
if 'goldCount' not in request.session:
request.session['goldCount'] = 0

Multiple forms with Flask keeps saying I haven't defined forms

I am trying to set up two different forms on the same Flask page with validators, but it keeps telling me my forms are not defined. I get error:
The code is designed to allow users to input a number and check if it is abundant, perfect, or deficient, and then with a separate form to allow users to define a range and get how many abundant, perfect or deficient numbers there are within that range.
My code is as follows:
from flask import Flask, render_template, request
from flask_wtf import Form
from wtforms import IntegerField
from wtforms.validators import InputRequired
from perfect_numbers import classify, listInRange
app = Flask(__name__)
app.config['SECRET_KEY'] = 'DontTellAnyone'
class PerfectForm(Form):
inputNumber = IntegerField('input a number', default=1, validators=[InputRequired(message='Please input an integer')])
class PerfectRangeForm(Form):
startNumber = IntegerField('input a number', default=1, validators=[InputRequired(message='Please input an integer')])
endNumber = IntegerField('input a number', default=1, validators=[InputRequired(message='Please input an integer')])
#app.route('/', methods=['GET', 'POST'])
def index():
form1 = PerfectForm(request.form, prefix="form1")
num = 1
Classify = classify(num)
if form.validate_on_submit() and form.data:
num = request.form1['inputNumber']
Classify = classify(form1.inputNumber.data)
return render_template('index.html', form1=form1, num=num, classify=Classify)
return render_template('index.html', num=1, form1=form1, classify=Classify)
#app.route('/aliRange', methods=['GET', 'POST'])
def aliRange():
form2 = PerfectRangeForm(request.form2, prefix="form2")
startNumber = 1
endNumber = 1
aliquot = 'abundant'
Classify = classify(num)
ListInRange = listInRange(startNumber, endNumber, aliquot)
if form2.validate_on_submit() and form2.data:
startNumber = request.form2['startNumber']
endNumber = request.form2['endNumber']
aliquot = request.form2['aliquot']
ListInRange = listInRange(startNumber, endNumber, aliquot)
return render_template('index.html', form2=form2, startNumber=startNumber, endNumber=endNumber, ListInRange=listInRange)
return render_template('index.html', form2=form2, startNumber=startNumber, endNumber=endNumber, ListInRange=listInRange)
if __name__ == '__main__':
app.run(debug=True)
index.html:
{% from "_formhelpers.html" import render_field %}
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>WTForms</title>
</head>
<body>
<div>
<form action="/" method="POST">
<dl>
{% if form1 %}
{{ form1.csrf_token }}
{{ render_field(form1.inputNumber) }}
{% endif %}
<input type="submit" value="submit1">
</dl>
</form>
</div>
<div>
{{ num }} is {{ classify }}
</div>
<div></div>
<div>
<form action="/aliRange" method="POST">
<div class="form-group">
<p>Input a start number and an end number to return a list of...</p>
<select class="form-control" action="/aliRange" name="aliquot" method="POST">
<option value = 'abundant'>Abundant</option>
<option value = 'perfect'>Perfect</option>
<option value = 'deficient'>Deficient</option>
</select>
<p>...numbers within that range</p>
<form action="/aliRange" method="POST">
<dl>
{% if form2 %}
{{ form2.csrf_token }}
{{ render_field(form2.startNumber) }}
{{ render_field(form2.endNumber) }}
{% endif %}
<input class="btn btn-primary" type="submit" value="submit">
</dl>
</form>
</div>
</form>
The {{ aliquot }} numbers between {{ startNumber }} and {{ endNumber }} are:
{{ listInRange }}
</div>
</body>
</html>
Error I get atm is: AttributeError: 'Request' object has no attribute 'form1'
EDIT:
You can simplify your code using a single view, using the submit value to differentiate the handling of the first form and the second one.
The modified code is:
class PerfectForm(Form):
inputNumber = IntegerField('input a number', default=1, validators=[InputRequired(message='Please input an integer')])
class PerfectRangeForm(Form):
startNumber = IntegerField('input a number', default=1, validators=[InputRequired(message='Please input an integer')])
endNumber = IntegerField('input a number', default=1, validators=[InputRequired(message='Please input an integer')])
aliquot = StringField('input a kind', default='perfect')
#app.route('/', methods=['GET', 'POST'])
def index():
form1 = PerfectForm(request.form, prefix="form1")
form2 = PerfectRangeForm(request.form, prefix="form2")
num = 1
Classify = classify(num)
startNumber = 1
endNumber = 1
aliquot = 'abundant'
ListInRange = listInRange(startNumber, endNumber, aliquot)
if request.form.get('submit') == 'submit-1':
if form1.validate_on_submit() and form1.data:
num = form1.data['inputNumber']
Classify = classify(num)
elif request.form.get('submit') == 'submit-2':
if form2.validate_on_submit() and form2.data:
startNumber = form2.data['startNumber']
endNumber = form2.data['endNumber']
aliquot = form2.data['aliquot']
ListInRange = listInRange(startNumber, endNumber, aliquot)
return render_template('index.html',
num=num, classify=Classify,
startNumber=startNumber, endNumber=endNumber, aliquot=aliquot, ListInRange=ListInRange,
form1=form1, form2=form2)
if __name__ == '__main__':
app.run(debug=True)
and the modified template index.html is:
{% from "_formhelpers.html" import render_field %}
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>WTForms</title>
</head>
<body>
<div>
<form action="/" method="POST">
<dl>
{{ form1.csrf_token }}
{{ render_field(form1.inputNumber) }}
<input type="submit" name="submit" value="submit-1">
</dl>
</form>
</div>
{% if num %}
<div>
{{ num }} is {{ classify }}
</div>
{% endif %}
<hr />
<div>
<form action="/" method="POST">
{{ form2.csrf_token }}
<div class="form-group">
<p>Input a start number and an end number to return a list of...</p>
<select class="form-control" action="/aliRange" name="aliquot" method="POST">
<option value = 'abundant'>Abundant</option>
<option value = 'perfect'>Perfect</option>
<option value = 'deficient'>Deficient</option>
</select>
<p>...numbers within that range</p>
<dl>
{{ render_field(form2.startNumber) }}
{{ render_field(form2.endNumber) }}
</dl>
<input class="btn btn-primary" type="submit" name="submit" value="submit-2">
</div>
</form>
<div>
The {{ aliquot }} numbers between {{ startNumber }} and {{ endNumber }} are:
{{ listInRange }}
</div>
</div>
</body>
</html>
OLD:
You are using form1 in the template but passing form inside the template context:
render_template('index.html', form=form1, num=num, classify=Classify)
You can either change form1 to form inside the template, or pass form1=form1 in the above line.
If you are rendering multiple forms inside the same template, you have to pass all the respective form variables: form1, form2, ... from all the views rendering that template. Otherwise the template rendering will raise the error you are seeing.
If you are interested in having a single form rendered among all the possible ones inside the template, you can use conditional rendering using
{% if form1 %}
<div>
<form action="/" method="POST">
<dl>
{{ form1.csrf_token }}
...
</dl>
</form>
</div>
{% endif %}
{% if form2 %}
<form action="/aliRange" method="POST">
...
</form>
{% endif %}
...
Also, your html seems incorrect to me, because you have a form nested inside another form. Not sure about what you are trying to obtain there.

Unable to get value selected in python from a dropdown using Flask

This question could be a duplicate but I have checked all the answers of such related questions and I haven't been able to solve it.
I am trying to get the value from a dropdown menu which consists of numbers. Then I want to compare the numbers with a value and display a text based on the comparison.
Eg
if value_selected_from_dropdown >3
display text
I am unable to get the text to display or even print the value of the option selected.
Here is the python file, web_plants.py
from flask import Flask, render_template,request, redirect, url_for
app = Flask(__name__)
def template(title = "HELLO!", text = ""):
templateDate = {
'text' : text
}
return templateDate
#app.route("/threshold", methods=['POST'])
def threshold():
tvalue= (request.form.get['tvalue']) #get value from dropdown
msg= ""
if tvalue>3:
msg= "rating above 3"
templateData = template(text = msg) #display text using template()
#templateData = template(text = tvalue) #tried to print the value selected
return render_template('index.html', **templateData)
if __name__ == "__main__":
app.run(host='0.0.0.0', port=80, debug=True)
index.html:
<!DOCTYPE HTML>
<html>
<head>
<link rel="stylesheet" type="text/css" href="{{ url_for('static',filename='style.css')}}" />
</head>
<body>
<h2> {{ text }} </h2>
<form action= "{{ url_for('threshold') }}" method="post>"
<p>
<select name= 'tvalue'>
<option value="10">10</option>
<option value="11">11</option>
<option value="15">15</option>
<option value="2">2</option>
<option value="1">1</option>
</select>
</p>
</form>
</body>
</html>
There are several ways to achieve this. Either you can give logic to the template itself or you can add the logic in the function threshold.
index.html
<h2> {{text}} </h2>
<form action= "{{ url_for('threshold') }}" method="POST">
<select name= 'tvalue'>
{% for tvalue in tvalues %}
{% if selected_tvalue == tvalue %}
<option value="{{ tvalue }}" selected='selected'>{{ tvalue }}</option>
{% else %}
<option value="{{ tvalue }}" >{{ tvalue }}</option>
{% endif %}
{% endfor %}
</select>
<input type="submit" value="Submit" />
</form>
OR,
{% if selected_tvalue > 3 %}
<h2> Selected value is greater than 3 </h2>
{% else %}
<h2> Selected value is less than or equal to 3 </h2>
{% endif %}
<form action= "{{ url_for('threshold') }}" method="POST">
<select name= 'tvalue'>
{% for tvalue in tvalues %}
{% if selected_tvalue == tvalue %}
<option value="{{ tvalue }}" selected='selected'>{{ tvalue }}</option>
{% else %}
<option value="{{ tvalue }}" >{{ tvalue }}</option>
{% endif %}
{% endfor %}
</select>
<input type="submit" value="Submit" />
</form>
server.py
def template(title = "HELLO!", text = ""):
templateDate = {
'text' : text,
'tvalues' : getTValues(),
'selected_tvalue' : -1
}
return templateDate
def getTValues():
return (10, 11, 15, 2, 1)
#app.route("/threshold", methods=['POST', 'GET'])
def threshold():
tvalue= -1 #default value
msg = ''
if request.method == "POST":
tvalue = int(request.form['tvalue'])
if tvalue> 3:
msg= "rating above 3"
#generating template data
templateData = template(text = msg)
templateData['selected_tvalue'] = tvalue
return render_template('index.html', **templateData)
Then access your form at path /threshold. I hope it helps.
In your html after your drop down block you may need something like
<input type="submit">
which will trigger the submit. I am not sure, selecting a value alone triggers the form submit.
By the way where are you rendering your page initially ? I would have something like:
#app.route('/')
#app.route('/index')
def index():
return render_template('index.html')
in the python code. There to get the value, I would try
tvalue= request.args.get('tvalue')
Well not 'form' but 'args', and normal brackets instead of squared ones. Finally the function where you are going to handle that 'templateData' might be missing too.
last note:
you might need GET method too:
#app.route("/threshold", methods=['GET', 'POST'])

Categories

Resources