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:
...
Related
I'm trying to store some data from a html form in a .txt file. But when I store data from my variable used to recieve data it give "None". But when I pass string directly it successfully store.
def write(request):
p_no = request.GET.get('p_no')
# temp = "% s" % p_no
# Str_value = '{}'.format(p_no)
temp = p_no.__str__()
with open('C:\\Users\\The Goat\\Desktop\\testp\\Files\\sample.txt', 'w+') as f:
testfile = File(f)
testfile.write(temp)+
testfile.close
f.close
return render(request,'index.html')
Perhaps in the form you use form method="post", and in the view you request request.GET.get.
The following code works for me(bboard replace with the name of your folder where the templates are located):
views.py
def form(request):
return render(request, 'bboard/index3.html')
def write(request):
p_no = request.GET.get('p_no')
temp = p_no.__str__()
with open('test12345.txt', 'w+') as f:
f.write(temp)
f.close
return HttpResponse(f"<h2>Name: {temp}")
index3.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
</head>
<body>
<h2>User form</h2>
<form method="get" action="{% url 'write'%}">
{% csrf_token %}
<p>Name:<br> <input name="p_no" /></p>
<input type="submit" value="Send" />
</form>
</body>
</html>
urls.py
urlpatterns = [
path("form/", form),
path("write/", write, name="write"),
]
My goal is to have a Flask app who let the user put a csv file and the app return an specific output.
Here's the output I want, let me show you how I done it in jupyter notebook :
for i in df['variable1'].unique():
data = df[(df['variable1'] == i)]
data['list'] = data['comms_clean'].apply(lambda x: str(x).split())
top = Counter([item for sublist in data['list'] for item in sublist])
mostcommon = pd.DataFrame(top.most_common(3))
mostcommon.columns = ['Common Word', 'Count']
print()
print('For the classe "{0}" who appears {1} time, here is the 3 most frequent word: '.format(i, data.shape[0]))
print()
print(mostcommon.head(3))
print()
And here's the result :
For the classe "classe1" who appears 389 time, here is the 3 most frequent word:
Common Word Count
0 word10 267
1 word20 149
2 word30 46
For the classe "classe1" who appears 657 time, here is the 3 most frequent word:
Common Word Count
0 word40 234
1 word50 89
2 word60 34
For the classe "classe3" who appears 250 time, here is the 3 most frequent word:
Common Word Count
0 word70 90
1 word80 30
2 word90 19
...
But I cannot figure it out how to transpose this into Flask.
Here's my app.py :
from flask import Flask, render_template, request
from werkzeug.utils import secure_filename
import os
import pandas as pd
ALLOWED_EXTENSIONS = {'csv', 'txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif'}
UPLOAD_FOLDER = 'uploads/'
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
def allowed_file(filename):
return '.' in filename and filename.rsplit('.',1)[1].lower() in ALLOWED_EXTENSIONS
#app.route('/', methods=['GET','POST'])
def upload_file(filename=None,column=None, data=None):
if request.method == 'GET':
render_template('index.html')
if request.method == 'POST':
if 'file' not in request.files:
flash("No file part")
return redirect(request.url)
file = request.files['file']
if file.filename == '':
flash("No selected file")
return redirect(request.url)
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
file_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
file.save(file_path)
df = pd.read_csv(file_path, delimiter = ';')
column = list(df)
data = [list(df[d]) for d in column]
df_head = df.head()
return render_template('index.html', data=data, tables=[df_head.to_html(classes='data')], titles=df.columns.values)
return render_template('index.html')
if __name__ == '__main__':
app.run(debug=True)
And here's my index.html :
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Upload File</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" media="screen" href="main.css" />
<script src="main.js"></script>
</head>
<body>
{% if data %}
{% for table in tables %}
{{titles[loop.index]}}
{{ table|safe }}
{% endfor %}
{% endif %}
<h1>Upload new File</h1>
<form method=post enctype=multipart/form-data>
<input type=file name=file>
<input type=submit value=Upload>
</form>
</body>
</html>
But this app give me the head() of the csv file uploaded, the specific output I want is way harder to implement so if you could help me, it would be awesome.
I think I need to create a dataframe with my most frequent word because Flask seems to need a dataframe but I'm not entirely sure.
Any suggestions ?
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'm trying to assign a session variable in one Template and pass it to another, but I keep getting KeyError: 'var' error. I'm not sure what I'm doing wrong here. My views.py looks as follows:
from flask import Flask, request, jsonify, session
from app import app
#app.route('/activity', methods=['GET', 'POST'])
def activity():
user = session['var']
location = {'mspace': 'Central Library'}
return render_template('activity.html',
location = location,
user = user)
#app.route('/', methods=['GET', 'POST'])
#app.route('/index', methods=['GET', 'POST'])
def index():
global checkCheck
print "starting"
if request.method == 'POST':
# print(request.data)
checkCheck = True
location = {'mspace': 'Central Library'}
user = {'nickname': request.args.get('name')}
session['var'] = user
# print user['nickname']
print session['var']
return render_template('index.html',
location = location,
user = user)
return render_template('index.html',
location = "test",
user = 'user')
and here's my activity.html:
<html>
<head>
<title>{{ location['mspace'] }} - Makerspace </title>
</head>
<body>
<h1>Hello, {{ user['nickname'] }} - what activity are you doing today:</h1>
<form action="" method="">
<h3> Choose your Activity</h3>
<select name="activity">
<option value='3dprinting'>3D Printing</option>
<option value='Minecraft'>Minecraft</option>
<option value='Arduino'>Arduino</option>
<option value='Wearables'>Wearables</option>
</select>
</body>
</html>
Here's my index.html:
<html>
<head>
<title>{{ location['mspace'] }} - Makerspace </title>
</head>
<body>
<h1>Hello, {{ user['nickname'] }}!</h1>
</body>
<script>
function httpGet(theUrl)
{
var xmlHttp = new XMLHttpRequest();
xmlHttp.open( "GET", theUrl, false );
xmlHttp.send(null);
return xmlHttp.responseText;
}
setInterval(checkFunc(), 1000);
function checkFunc(){
var json = httpGet("/getSignIn");
console.log("yes!");
obj = JSON.parse(json);
console.log(obj.newCheckin);
if(obj.newCheckin){
window.location.replace("http://127.0.0.1:5000/activity");
}
else{
setInterval(checkFunc(), 1000);
}
}
</script>
</html>