Use Flask path string to refer to variables - python

I have the following Flask app. It renders a html page with a form for each cell of the dataframe and allows the user to edit the cells and post the form data. The app then updates the dataframe.
'''
from flask import Flask, render_template, url_for, request, redirect
import pandas
app = Flask(__name__)
df_abc = pandas.read_excel('source1.xlsx')
#app.route('/modify/', methods=['POST', 'GET'])
def modify():
if request.method == 'POST':
global df_abc
df_abc = update_df_function() # this function returns an updated df based on the POST data
return redirect(url_for('modify'))
else:
table_data = df_abc.to_dict(orient='records')
return render_template('modify.html', table_data=table_data)
'''
However, I would like the following to work:
from flask import Flask, render_template, url_for, request, redirect
import pandas
app = Flask(__name__)
df_abc = pandas.read_excel('source1.xlsx')
df_xyz = pandas.read_excel('source2.xlsx')
#app.route('/modify/<name>', methods=['POST', 'GET'])
def modify(name):
if request.method == 'POST':
global name
name = update_df_function() # this function returns an updated df based on the POST data
return redirect(url_for('modify'))
else:
table_data = name.to_dict(orient='records')
return render_template('modify.html', table_data=table_data)
'''
This app would get the variable name from the Flask path. How can I set the variable names in the modify function (e.g. global df_abc) by using the string < name > from the Flask path? I.e. posting data from www.site.com/modify/df_abc should update df_abc, ./modify/df_xyz should update df_xyz etc.
Any help would be greatly appreciated. Thanks!

The answer is using globals() with globals()[name], as shown below, and explained in this answer https://stackoverflow.com/a/1373201
from flask import Flask, render_template, url_for, request, redirect
import pandas
app = Flask(__name__)
df_abc = pandas.read_excel('source1.xlsx')
df_xyz = pandas.read_excel('source2.xlsx')
#app.route('/modify/<name>', methods=['POST', 'GET'])
def modify(name):
if request.method == 'POST':
globals()[name] = update_df_function() # this function returns an updated df based on the POST data
return redirect(url_for('modify'))
else:
table_data = globals()[name].to_dict(orient='records')
return render_template('modify.html', table_data=table_data)

Related

Flask redirect(url_for) with arguments

I'm new to building web apps using Flask and having trouble using redirect(url_for)
from flask import Flask, render_template, request, redirect, url_for
app = Flask(__name__)
def getSomeList(paramsFromHTML):
return someList
#app.route("/", methods=["GET", "POST"])
def index():
if request.method == "POST":
myData = getSomeList(paramsFromHTML)
return redirect(url_for("show_data", this_data=myData))
else:
# Show the default page for GET requests
return render_template("welcome.html")
#app.route("/show_data", methods=["GET", "POST"])
def show_data(this_data):
return render_template("show_data.html", data=this_data)
Once I get some details from HTML in my main index page, I need to route it to the show_data view function.
The function has a parameter (this_data). However, there is no parameter in the route itself - like "/show_data/<string:something>" It is just "/show_data"
I get the below error when trying this.
TypeError: show_data() missing 1 required positional argument: 'this_data'
Is it mandatory to have some kind of a parameter in the url route as well?
Is there any work around I can try for my use case?
I was able to get this working after removing the args part (this_data) from my show_data function and use the below to get the value -
this_data = request.args.get('data')

None value returned when trying to access variables across flask sessions

from flask import Flask, session, request, render_template
import model //model.py
app = Flask(_name__)
session.key = "randomkey"
#app.route("/", methods = ['POST', 'GET'])
def hello():
if request.method == 'POST':
//Some cide that takes input from index.html and stores in python variables
prediction = model.make_prediction(modelinput)
session["prediction"] = prediction
return render_template("index.html")
#app.route("/prediction", methods = ['POST', 'GET'])
def submit():
final_prediction = session.get("prediction", None)
return render_template("prediction.html", predic = final_prediction)
Now even though I use a session variable to pass the value between the sessions, I get a None value as the output. Why is that?
Try adding this line in your code:
from flask import Flask, session, request, render_template
import model //model.py
app = Flask(_name__)
app.config["SECRET_KEY"] = "topSecret"

Having trouble with jsonify in Flask

I am fairly new to Flask and am currently working on a project whose goal is to transcribe mp3 files into JSON. I decided to attempt to use Flask, but it's been more challenging than I thought.
As of right now, I am able to display a example JSON file in one of my html pages, but I have not been able to format it. I looked at some previous answers that told me to use jsonify, but it hasn't worked apparently. If you guys could give me a hand, any kind of comment would be really apreciated. Here is my code:
from flask import Flask, render_template, url_for, request, redirect, json, jsonify
import json
import os
from pathlib import Path
app = Flask(__name__)
#app.route('/')
def index():
return render_template('index.html')
#app.route('/upload', methods=['POST'])
def upload():
file = request.files['inputFile']
if Path(file.filename).suffix == '.mp3':
filename = os.path.join(app.static_folder, 'data', 'json_test.json')
with open(filename) as json_test:
data = json.load(json_test)
return render_template('index2.html', data=data)
else:
return render_template('erro.html')
if __name__ == "__main__":
app.run(debug=True)

How to make a dataframe global inside a function and use it in another function in python flask

I am creating a Dataframe by taking input file from user on a website and processing it.After that I want the user to download the final result in a csv file.For that a Dataframe is required from previous function.
I have tried passing the dataframe but it is giving me error as it is defined in another function.
My code is
from flask import Flask, render_template, request, redirect
from werkzeug import secure_filename
app = Flask(__name__)
#app.route('/uploader', methods = ['GET','POST'])
def upload():
new=nrecs[['UserID','ProductID','Rating']]
new['Recommendations'] = list(zip(new.ProductID, new.Rating))
res=new[['UserID','Recommendations']]
res_new=res['Recommendations'].groupby([res.UserID]).apply(list).reset_index()
pd.options.display.max_colwidth = 500
return render_template('simple.html', tables=[res_new.to_html(classes='data')], titles='')
#app.route('/download-csv', methods = ['GET'])
def download():
return res_new.to_csv('Recommendations.csv')
This is a small snipet of my code not the full code.
When a user will click on download recommendations button it should download the csv file.
Is there any other way around it can be done.
You can also store the file on the server and send it to the user in your download-csv route. Here is a send file tutorial
from flask import Flask, render_template, send_file
app = Flask(__name__)
#app.route('/uploader', methods = ['GET','POST'])
def upload():
new=nrecs[['UserID','ProductID','Rating']]
new['Recommendations'] = list(zip(new.ProductID, new.Rating))
res=new[['UserID','Recommendations']]
res_new=res['Recommendations'].groupby([res.UserID]).apply(list).reset_index()
# store the dataframe on the server.
res_new.to_csv('Recommendations.csv')
pd.options.display.max_colwidth = 500
return render_template('simple.html', tables=[res_new.to_html(classes='data')], titles='')
#app.route('/download-csv', methods = ['GET'])
def download():
# return the CSV file to the user here.
return send_file('Recommendations.csv')
You can try using a session object. See this question/answer. However, depending on the size of the dataframe, and what you are ultimately trying to do, this may not be the best way to do this. If you are trying to set up upload/download routes, storing the file on the server/elsewhere and then sending it to the user when they request it may be a better solution.
from flask import Flask, render_template, session
app = Flask(__name__)
# secret key is needed for session
app.secret_key = 'your secret key'
#app.route('/uploader', methods = ['GET','POST'])
def upload():
new=nrecs[['UserID','ProductID','Rating']]
new['Recommendations'] = list(zip(new.ProductID, new.Rating))
res=new[['UserID','Recommendations']]
res_new=res['Recommendations'].groupby([res.UserID]).apply(list).reset_index()
session['reco_df'] = res_new
pd.options.display.max_colwidth = 500
return render_template('simple.html', tables=[res_new.to_html(classes='data')], titles='')
#app.route('/download-csv', methods = ['GET'])
def download():
return session['reco_df'].to_csv('Recommendations.csv')

Flask, WTForms open multiple urls in new tab

I am building a small app with Flask to reboot multiple IP-based devices. I want to have a checklist of the devices that when I can go through and on submit it will open that ip/rebootpage.html. As of right now my code tries to combine all of the data from the form/rebootpage. Here is what I have so far:
app.py
from flask import Flask, render_template, redirect
from flask_wtf import FlaskForm
from wtforms import widgets,SelectMultipleField
app = Flask(__name__)
app.config['SECRET_KEY'] = "565&SDdsa7fgSdst7%6"
Test_Choices = [('10.202.214.196', '#61'), ('10.202.214.197', '#62')]
Test_Choices_NR = [('10.202.214.198', 'Net Relay 1')]
class RebootForm(FlaskForm):
available = SelectMultipleField('Available', choices=Test_Choices,
option_widget=widgets.CheckboxInput(),
widget=widgets.ListWidget(prefix_label=False))
availableNR = SelectMultipleField('Available Net Relays', choices=Test_Choices_NR,
option_widget=widgets.CheckboxInput(),
widget=widgets.ListWidget(prefix_label=False))
#app.route('/form', methods=['GET', 'POST'])
def form():
form = RebootForm()
if form.validate_on_submit():
list = '{}'.format(form.available.data).replace("'", "").replace("[", "").replace("]", "")
for each in list:
return redirect('http://{}/rc.cgi?L=uirreboot.html&c=99'.format(each))
return render_template('form.html', form=form)
if __name__ == '__main__':
app.run(debug=True)
A little asking around the IRC got me to my answer. The answer is I have to use requests (not request, there are 2 different things). My final code looks like this and works great. Note that requests makes the requests without ever opening the page.
app.py
from flask import Flask, render_template, redirect, url_for
import requests
from flask_wtf import FlaskForm
from wtforms import widgets,SelectMultipleField
app = Flask(__name__)
app.config['SECRET_KEY'] = "565&SDdsa7fgSdst7%6"
All_Selected = [('Everything', 'Entire Site')]
Test_Choices = [('10.202.214.196', '#61'), ('10.202.214.197', '#62')]
Test_Choices_NR = [('10.202.214.198', 'Net Relay 1')]
class RebootForm(FlaskForm):
all_selected = SelectMultipleField('Select All', choices=All_Selected,
option_widget=widgets.CheckboxInput(),
widget=widgets.ListWidget(prefix_label=False))
available = SelectMultipleField('Available', choices=Test_Choices,
option_widget=widgets.CheckboxInput(),
widget=widgets.ListWidget(prefix_label=False))
availableNR = SelectMultipleField('Available Net Relays', choices=Test_Choices_NR,
option_widget=widgets.CheckboxInput(),
widget=widgets.ListWidget(prefix_label=False))
#app.route('/form', methods=['GET', 'POST'])
def form():
form = RebootForm()
ugly_messages = []
if form.validate_on_submit():
ip_addresses = form.available.data
for ip_address in ip_addresses:
try:
requests.get('http://{}/rc.cgi?L=uirreboot.html&c=99'.format(ip_address))
ugly_messages.append('rebooting {}'.format(ip_address))
ugly_messages.append('Please wait 30 secs.')
except Exception:
ugly_messages.append('{} did not reboot. It may be offline.'.format(ip_address))
ip_addressesNR = form.availableNR.data
for ip_addressNR in ip_addressesNR:
try:
requests.get('http://{}/setup.cgi?L=uireboot2.html&R'.format(ip_addressNR))
ugly_messages.append('rebooting {}'.format(ip_addressNR))
ugly_messages.append('Please wait 30 secs.')
except Exception:
ugly_messages.append('{} did not reboot. It may be offline.'.format(ip_addressNR))
return "<br/>".join(ugly_messages)
return render_template('form.html', form=form)
if __name__ == '__main__':
app.run(debug=True)

Categories