I ask a very similar question like this yesterday and was directed here. I took what was posted there (using a session) to take in a user input, update a second page with a data table. However, If I get to that second route through any other means, it resorts back to the default which is an empty data table. So I'm thinking that the variable is not being updated and saved or being rewritten. Code below
#app.route('/', methods=['GET','POST'])
def index():
loadform = LoadDataForm()
session['dataset'] = toy_data.get_empty_df()
if loadform.validate_on_submit():
dataset, headers = toy_data.get_dataset(int(loadform.selectToyData.data))
session['dataset'] = dataset
session.modified = True
return render_template('DataTable.html',dataset=dataset)
return render_template('LoadData.html',form=loadform)
#app.route('/DataTable', methods=['GET','POST'])
def index_data():
dataset = session.get('dataset',None)
return render_template('DataTable.html',dataset=dataset)
The data you are setting is added to the session.
That’s why it’s not set in a different session.
Related
I am using flask-cache (FileSystemCache)to store an entire table worth of data (to prevent constant database IO)
This works great, and really speeds up the reading of the records, but my app also allows users to "update rows" in the database.
I am fine with the IO in this case, however I would also like to update the local cache of the row in this situation (because if the user revisits the last updated row, the cache will be what was previously fetched from the database and will not reflect the most recent user update).
I can see the cache is generated and it is stored in some binary way (pickle?), which I can see contains all the rows (and as mentioned, the cache is working as expected for "reads"). I don't know how to either "get" or "set" specific rows within the cache file though.
Below is the simplified code of what I am doing:
#cache.cached(timeout=500, key_prefix='all_docs')
def cache_all_db_rows(table_name):
engine = create_sql_alchemy_engine()
connection = engine.connect()
results = connection.execute(stmt).fetchall()
return [row for row in results]
#site.route('/display/<doc_id>', methods=["GET", "POST"])
#login_required
def display(doc_id):
form = CommentForm(request.form)
results = cache_all_db_rows(table_name)
if request.method == "POST":
if form.validate_on_submit():
comments = form.comment.data
relevant = form.relevant.data
database_rate_or_add_comment(comments=comments, relevant_flag=relevant, doc_id=doc_id)
# Ideally I would set the update to the cache here (after a successful db update)
cache.set("foo", comments)
return render_template("display.html", form = form)
I tried a few things, but can't seem to query the cache (pickle file?)... I tried adding code to query what is actually in the cache file by doing this:
obj = []
file_name = "./cache/dfaec33f482d83493ed6ae7e87ace5f9"
with open(file_name,"rb") as fileOpener:
while True:
try:
obj.append(pickle.load(fileOpener))
except EOFError:
break
app.logger.info(str(obj))
but I am receiving an error: _pickle.UnpicklingError: invalid load key, '\xfb'.
I am not sure how to interact with the flask-cache.
Question
I have created a dynamic route as /update/<randomString> in my Flask app.py file, where randomString is a randomly generated string with the length of 50. However if I search for /update/1 I am able to view the same dynamic route /update/<randomString> without any error! Can anyone explain why is it so?
See what I've tried so far:
#app.route('/')
def index():
randomString = ''.join(secrets.choice(string.ascii_uppercase+string.digits+string.ascii_lowercase) for k in range (50))
session['randomString'] = str(randomString)
return render_template('index.html')
#app.route('/update/<randomString>')
def update(randomString):
if 'randomString' in session:
randomString = session['randomString']
return render_template('update.html')
else:
return 'error...'
Link of the dynamic page at update.html page, where random string is passed with the help of session(defined at index.html page).
Dynamic page
Edit: I am also able to view dynamic route when I click on the link defined above and my URL section shows that long randomString. Problem is: I can access the same route when I search for http://127.0.0.1:5000/update/1
Screenshot one
Screenshot two
While storing the random string, the key you use is randomString. So you are storing the random string in a dict like
session['randomString'] = '1234567890'
Then when you access the session in the /update route you are just checking if session has a key named randomString. You should also check if session['randomString'] == '1234567890' and render the page only if the random string in session is the same as you created in the / path. You can replace the if with
if 'randomString' in session and session['randomString'] == randomString :
This question already has answers here:
Are global variables thread-safe in Flask? How do I share data between requests?
(4 answers)
Closed 1 year ago.
App works perfectly locally but crushes after deployment- seems like it does so when I get to points where operations on variables take place.
I've looked up other similar questions but with no luck.
I assume I am making some fundamental mistake however I am not able to identify it. I was thinking perhaps something with Flask app session settings and the way requests are handled.
It's my first independent project and I realize that there must be more pythonic way of achieving things however I was just focusing on problem solving with this one.
After deployment app either crushes (NoneType object) or goes into the loop looking like variables are not being set at all- none of which happens when app is tested locally.
Fragment of code (up to the point where app crushes- I don't want to spam entire code here):
from flask import Flask, render_template, request, flash, redirect, url_for
import codecs
import datetime
from sq_search import *
from list_creator import list_creator
app = Flask(__name__)
app.secret_key= 'dev'
# Global variables created- to avoid "not defined error" in certain parts of script-
# depending on user choice
stype=None
namesearch=None
final_name=None
results=None
ticker_result=None
name_result=None
company=None
from_date=None
to_date=None
disable_1st=None
email_name=None
#app.route('/')
def home():
# Setting global variables used in search to None- in case user stops search, goes to
# other page and returns back to search- avoids errors
global stype, namesearch, final_name, results, ticker_result, name_result, company
stype=None
namesearch=None
final_name=None
results=None
ticker_result=None
name_result=None
company=None
return render_template("home.html")
#app.route('/seng/', methods=['POST','GET'])
def seng():
global stype, namesearch, final_name, results, ticker_result, name_result
search_options_title="Chosen search options:"
# Using 'try except' block to avoid errors- in case user presses go back or refreshes the
# page the script will execute further and eventuall assign variables to None letting
# the user start new search rather than returning error
if stype == None:
try:
if request.method=="POST":
global search_options
stype=request.form["stype"]
if stype == 'name':
search_options=[">Chosing by Name"]
return render_template("seng.html", pic1="pic1.html", search_options=search_options_title+"<br><br>", search_by=search_options[0],
choice2="choice2.html")
if stype == 'ticker':
search_options=[">Chosing by ticker"]
return render_template("seng.html", pic1="pic1.html", search_options=search_options_title+"<br><br>", search_by=search_options[0],
choice2="choice2tick.html")
except:
pass
if namesearch==None and stype=='ticker':
try:
if request.method=="POST":
ticker_search=request.form["tickersearch"].upper()
get_ticker(ticker_search)
if ticker_result:
stype=None
return redirect(url_for('final_stage'))
else:
ticker_search=None
notick_error="<p style='font-size: 1.4vw;color: red'>Ticker incorrect! Inster S&P 500 ticker, search again by name or browse all companies from main menu</p>"
return render_template("seng.html", pic1="pic1.html", search_options=search_options_title+"<br><br>", search_by=search_options[0],
choice2="choice2tick.html", notick_error=notick_error)
except:
stype=None
pass
elif namesearch==None and stype=='name':
if len(search_options) > 1: # Delets previously used search from right side menu if there was one already
del search_options[1]
if request.method=="POST":
try:
namesearch=request.form["namesearch"]
if namesearch != None:
get_names(namesearch)
if results:
list_creator(results) # Creates HTML script with drop down list of all matches
search_options.append(namesearch)
number_of_options=f"<br><p style='font-size: 1.3vw'>Number of matching results: {len(results)}</p>"
results=None
namesearch=None
return render_template("seng.html",pic1="pic1.html", pic2="pic2.html", search_options=search_options_title+"<br><br>",
search_by=search_options[0]+"<br><br>", search_name=">Look for: '"+search_options[1]+"'<br>",
number_of_options=number_of_options, choice3="choice3.html")
else:
noname_error= "<br><p style='font-size: 1.4vw;color: red'>No matches- no such company in S&P 500. Broaden the search or browse all companies in main menu</p>"
results=None
namesearch=None
return render_template("seng.html", pic1="pic1.html", search_options=search_options_title+"<br><br>", search_by=search_options[0],
choice2="choice2.html", noname_error=noname_error)
except:
stype=None
namesearch=None
results=None # Setting all variables to None- in case user went back a page during search-
ticker_result=None # otherwise would return an error
final_name=None
name_result=None
if final_name==None:
try:
if request.method=="POST":
final_name=request.form["name_final"]
name_result=get_all_byname(final_name) # Function retrives full data based on final user choice from drop down list
return redirect(url_for('final_stage'))
except:
pass
else:
namesearch=None # Same reason as previously- avoiding errors
stype=None
final_name=None
results=None
ticker_result=None
name_result=None
return render_template("seng.html", choice1="choice1.html")
The interpreter is confused about choosing definition for variable. Why do you keep global in function? Anything outside function is global. In case of switching contexts, you could use Flask session or Flask g.
Official Documentation
I am working on a site using Flask that is pulling data from an API, processing it into JSON, and then dynamically loading it throughout the site as needed. I am having an issue with matching the URL appropriately while at the same time efficiently loading what data I need.
Here is my main file:
import requests
from flask import Flask, render_template
app = Flask(__name__)
url = 'https://omgvamp-hearthstone-v1.p.mashape.com/cards'
myHeaders={
"X-Mashape-Key": 'key-here',
"Accept": "application/json"
}
r = requests.get(url, headers=myHeaders)
cards = r.json()
badSets = ['Promo', 'Hall of Fame', 'Tavern Brawl', 'Hero Skins', ' Missions', 'Credits', 'System', 'Debug']
#app.route('/')
def index():
return render_template('index.html', cards=cards, badSets=badSets)
#app.route('/<setName>', methods=['GET'])
def set(setName):
return render_template('set.html', cards=cards, setName=setName, badSets=badSets)
#app.route('/<setName>/<cardName>', methods=['GET'])
def individualCard(setName, cardName):
return render_template('card.html', cards=cards, setName=setName, cardName=cardName, badSets=badSets)
First, I'd prefer to not have to pass each html page all of my data. Is there some way to pull only what is needed and ignore the rest?
Second, I would like to pass a dictionary object i.e.
if card['name'] == card[setName][--index--][cardName]:
pass card object to html page here
How could this be achieved, and is it possible without having to use a for-loop through all of my data?
I'm happy to load my html pages if needed.
Assuming the basic structure of your parsed json data looks like this (a dictionary with lists of dictionaries):
{
"Basic": [{"cardId": 4711, ...}, {"cardId": 4712, ...}, ...],
"Fancy": [...],
...
}
You could rewrite:
#app.route('/<setName>', methods=['GET'])
def set(setName):
cardset = cards.get(setName)
return render_template('set.html', cardset=cardset)
This extracts the card set we are looking for by the dictionary key, according to the assumed data structure above.
Then in the template, instead of cardName, pass the cardId and rewrite the other route:
#app.route('/<setName>/<cardId>', methods=['GET'])
def individualCard(setName, cardId):
cardset = cards.get(setName)
matches = [x for x in cardset if x['cardId'] == cardId]
card = matches[0]
return render_template('card.html', card=card)
This uses list comprehension to extract a list of matches (everything that has the cardId we are looking for) from our selected cardset, and should be a list with a single element. We return the first element to the template for rendering.
Now this obviously does not do any error checking, for example the dictionary key we passed might be wrong and not be found, the cardId might not be found, or more interestingly there might be more than one result for the cardId we passed.
But this would be the general idea on how to approach this.
Also note I've left out badSets for clarity in the example, I'm assuming this are card sets that are forbidden, or for testing purposes.
For this case, you'd want to check the dictionary key first before looking up the set, and show an error page or something maybe:
#app.route('/<setName>', methods=['GET'])
def set(setName):
if setName in badSets:
return render_template('error.html')
cardset = cards.get(setName)
return render_template('set.html', cardset=cardset)
Disclaimer: This is coming purely from memory and it is late, so there might be an error here or there...
I am posting a JSON object back to the server side and retrieving that information through a request. Right now this is my code for my views.py
#csrf_exempt
def save(request):
if request.method == 'POST':
rawdata = request.body
JSONData= json.dumps(rawdata)
return HttpResponse(rawdata)
when I return rawdata my response looks like this:
[{"time_elapsed":"0","volts":"239.3","amps":"19.3","kW":"4.618","kWh":"0","session":"1"},...]
when I return JSONdata my response looks like this:
"[{\"time_elapsed\":\"0\",\"volts\":\"239.1\",\"amps\":\"20.8\",\"kW\":\"4.973\",\"kWh\":\"0\",\"session\":\"1\"},....]
which response is better when trying to insert this data into a sqlite database using Python/Django?
Also how would I start a loop for this do I have to do this kind of code?
conn = sqlite3.connect('sqlite.db')
c = conn.cursor()
c.execute("INSERT STATEMENTS")
I assume I have to do a loop for the INSERT STATEMENTS portion of that code, but I don't have any key to work off of. In my data everything between {} is one row. How do I iterate through this array saying everytime you see {...data...} insert it into a new row?
Here is how I eventually solved my problem. It was a matter of figuring out how to translate the JSON object to something python could recognize and then writing a simple loop to iterate through all the data that was produced.
#csrf_exempt
def save(request):
if request.method == 'POST':
rawdata1 = request.body
rawdata2 = json.loads(rawdata1)
length = len(rawdata2)
for i in range(0,length,1):
x = meterdata(time_elapsed=rawdata2[i]['time_elapsed'], volts=rawdata2[i]['volts'], amps=rawdata2[i]['amps'], kW=rawdata2[i]['kW'], kWh=rawdata2[i]['kWh'], session=rawdata2[i]['session'])
x.save()
return HttpResponse("Success!")
The big differences is the json.loads rather than dumps and in the for loop how to access the newly converted data. The first bracket specifies the row to look in and the second specifies what item to look for. for the longest time I was trying to do data[0][0]. May this help anyone who finds this in the future.
probably if you need to store that data in a db is best to create a model representing it, then you create a ModelForm with associated your model for handling your POST.
In this manner saving the model to the db is trivial and serializing it as a json response is something like
data = serializers.serialize('json',
YourModel.objects.filter(id=id),
fields=('list','of','fields'))
return HttpResponse(data, mimetype='application/json')