I want to read request argument and set it in some variable so that I should be able to access it anywhere down the line.I tried to use g and call context but it is giving me errors like
'Working outside of application context.'
Is it possible to achieve it using Flask?
Is there alternative solution to this problem?
Storing values globally not the best solution. And you can't store value in flask.g and expect to be available in the next request, well it's not. So I advise you to look into database or session to store value and access anywhere.
from flask import Flask, g
app = Flask(__name__)
#app.route("/")
def index():
if "count" not in g:
g.count = 0
g.count += 1
print(g.count)
return "This is index"
Use app_context. It keeps track of the application-level data during a request, CLI command, or other activity.
Read link for more infrmation
Example:
from app import app
with app.app_context():
print("Set or Access request variable")
Related
how can I dynamically pass all of the GET parameters from one url to another via flask?
This is currently what I am doing:
import os
from flask import Flask,redirect
from flask import request
from flask import url_for
app = Flask(__name__)
#app.route('/')
def hello():
return redirect(url_for("https://myurl.com", **request.args))
if __name__ == '__main__':
# Bind to PORT if defined, otherwise default to 5000.
port = int(os.environ.get('PORT', 5000))
app.run(host='0.0.0.0', port=port)
I can't really do it statically. What I am trying to accomplish:
myflaskserver:5000/page?url=google.com&header=body&identity=flash -> https://myurl.com/page?url=google.com&header=body&identity=flash
myflaskserver:5000/dance?url=dance.com&function=dancer&move=quality-> https://myurl.com/dance?url=dance.com&function=dancer&move=quality-
myflaskserver:5000/quit?host=google.com&language=english&password=test1234-> https://myurl.com/quit?host=google.com&language=english&password=test1234
With minimal code, without procedurally having to use if statements, or doing it statically with GET parameters for each page.
Thank you.
Because of the way that the question is phrased, it seems that you are looking for a way to perpetuate the url parameters only. In other words, you're not asking how to perpetuate the url page path (or "routes" in flask terminology), perhaps because you already have a strategy for that in mind.
If that assumption is incorrect, see my note near the bottom of this answer.
It also seems that you prefer passing the parameters as url parameters (versus passing the same data in the request header or payload).
If both these assumptions are correct, then the following approach may work for you:
Use the query_string method of request. This method returns all the url parameters as a bytes object (meaning you probably will need to decode it to a string if you wish to join it to your new url string).
import os
from flask import Flask,redirect
from flask import request
app = Flask(__name__)
#app.route('/')
def hello():
request_parameters = request.query_string.decode('utf-8')
return redirect("https://myurl.com?{0}".format(request_parameters))
if __name__ == '__main__':
# Bind to PORT if defined, otherwise default to 5000.
port = int(os.environ.get('PORT', 5000))
app.run(host='0.0.0.0', port=port)
Given the first url in your example...
myflaskserver:5000/page?url=google.com&header=body&identity=flash
...the statement request.query_string.decode('utf-8') would return the string "url=google.com&header=body&identity=flash", which is then appended to your endpoint "https://myurl.com?".
Notice ? needs to be added to the endpoint before joining with request.query_string.
Passing page paths (i.e. routes)
This was not explicitly asked in the question, so I won't go into much detail. But if you need to parse the route from the request, you could use request.url_rule, which will return everything after the domain and before the url parameters.
import os
from flask import Flask,redirect
from flask import request
app = Flask(__name__)
#app.route('/hello')
def hello():
request_parameters = request.query_string.decode('utf-8')
route = request.url_rule
return redirect("https://myurl.com{0}?{1}".format(route,request_parameters))
if __name__ == '__main__':
# Bind to PORT if defined, otherwise default to 5000.
port = int(os.environ.get('PORT', 5000))
app.run(host='0.0.0.0', port=port)
Or you could look into flask.referrer, which will return the referring url from the request header if it is available, which it sometimes isn't, such as in cross-origin scenarios of local testing.
Sidebar
For the information of anyone passing by this post, it may be helpful to mention why the request as written in the question will fail:
When the endpoint "https://myurl.com" of url_for is called, it will fail because the method expects an endpoint (or route, in flask terminology) defined by your app (versus an external endpoint with schema and domain) when called from an active request like this.
I am currently running into an issue deploying a Flask app on Amazon's EB2 service. The Flask app works locally. When it is deployed, however, it only works for the first person who clicks the link. After that it throws the following error:
Internal Server Error The server encountered an internal error and was
unable to complete your request. Either the server is overloaded or
there is an error in the application.
The error it is throwing out concerns the Flask session - it becomes empty after routing from one site to another. I also noticed that the before_first_request function detailed below is ran only once, for the first user, and never again - which is even more bewildering.
Here's the minimal example:
from flask import Flask, render_template, request, session, url_for
application = Flask(__name__)
application.secret_key = "mysecretkey"
#application.before_first_request
def before_first_request():
""" these commands are run before the first request"""
# setup logging
application.logger.setLevel(logging.INFO)
application.logger.info('starting up Flask')
# clear session
session.clear()
# load in PID
session['pid'] = 123
# add parameters to the session
params = dict()
params['parameter'] = 0
session['params'] = params
application.logger.info(session) # it is printing the session as expected
return 'OK'
#application.route('/')
def main():
""" landing page """
application.logger.info(session) # empty
application.logger.info(application.secret_key) # as expected
params, results = session.pop('params'), session.pop('results') # throws out the error
return render_template('empty_template.jinja', args = session)
I am wondering if anyone might know what is going on how to resolve the issue?
I managed to solve it.
The error was that #before_first_request wrapper actually only ran once before first request ever made to the app. Hence, the session was actually only created and populated once.
I fixed that error by adding the call to before_first_request function at the top of the main function.
I am trying to use Python - Flask to test the StatusCallback in Twilio, however, I am not getting any results, not sure what I am missing. I am using ngrok as well.
This is the code:
from flask import Flask, request, abort
import logging
logging.basicConfig(level=logging.INFO)
app = Flask(__name__)
#app.route('/webhook', methods =['POST', 'GET'])
def webhook():
status=request.values.get(['CallSid', 'From', 'To', 'Direction'])
logging.info('Status: {}'.format(status))
return ('', 204)
if __name__ == '__main__':
app.run(debug=True)
When I make a call, from the image I attached, you will notice I am not getting any results. Could you please advise what I may be missing? Thanks.
Twilio developer evangelist here.
When you create a tunnel with ngrok, a URL is set up that looks like https://RANDOMSUBDOMAIN.ngrok.io, make sure you are using the entire URL, including the subdomain.
When ngrok is running there is also a dashboard you can check to ensure that requests are being made to your ngrok URLs. You can reach this dashboard at http://localhost:4040. You can also use this to check the request parameters that are being sent.
Finally, you might have trouble with request.values.get and passing an array of keys. The get method of request.values only takes a single key, not an array.
As you pointed out in the comments, you can use request.form.to_dict(flat=False) to get a dictionary of the parameters instead. If you want to destructure that further into separate variables in a single line, you can use itemgetter from the operator module, like this:
from operator import itemgetter
#app.route('/webhook', methods =['POST', 'GET'])
def webhook():
parameters=request.form.to_dict(flat=False)
CallSid, From, To, Direction = itemgetter('CallSid', 'From', 'To', 'Direction')(parameters)
logging.info('CallSid: {}'.format(CallSid))
return ('', 204)
I have an endpoint in my API like below:
from flask import Flask
app = Flask(__name__)
#app.route('/price/<path:url>/')
def Ex(url):
return {'urlwas':url}
app.run()
The problem is that when I call the API with this http://127.0.0.1:5000/price/https://puresourceindia.in/store/index.php/?route=product/product&product_id=479
it should return this {"urlwas":"https://puresourceindia.in/store/index.php/?route=product/product&product_id=479"}
but it returns {"urlwas":"https://puresourceindia.in/store/index.php"}
I am unable to understand what is happening here, and how to tackle this situation?
You have to URL encode the parameter, the call should become:
http://127.0.0.1:5000/price/https%3A%2F%2Fpuresourceindia.in%2Fstore%2Findex.php%2F%3Froute%3Dproduct%2Fproduct%26product_id%3D479
and the result then becomes the one expected:
{"urlwas":"https://puresourceindia.in/store/index.php/?route=product/product&product_id=479"}
See here how to URL encode your string: https://www.urlencoder.org/
I am using:
Python 3.6.1
Flask 0.12.2
Section on session of Flask documentation says that:
This is a proxy.
and section on proxies elaborates that:
Some of the objects provided by Flask are proxies to other objects.
The reason behind this is that these proxies are shared between
threads and they have to dispatch to the actual object bound to a
thread behind the scenes as necessary. ...
If you need to get access
to the underlying object that is proxied, you can use the
_get_current_object() method
This all is pretty much straightforward.
But when I try the following:
from flask import (
Flask,
session,
)
app = Flask(__name__)
app.secret_key = 'some random secret key'
#app.route('/')
def index():
print("session ID is: {}".format(id(session)))
print("session._get_current_object() ID is: {}".format(id(session._get_current_object())))
print('________________________________')
return 'Check the console! ;-)'
each time I make a request to / — the value of id(session._get_current_object()) is different, while id(session) remains the same.
Following Flask documentation, quoted above, it should be the other way around. So why is this happening?
UPDATE
inspired by brunns's suggestion in the comments to his answer, that there is one underlying object per thread
Here is some code, to test assumption that there is one underlying session object (session._get_current_object()) per thread:
import threading
from flask import (
Flask,
session,
)
app = Flask(__name__)
app.secret_key = 'some random secret key'
#app.route('/')
def index():
print("session ID is: {}".format(id(session)))
print("session._get_current_object() ID is: {}".format(id(session._get_current_object())))
print("threading.current_thread().ident is: {}".format(threading.current_thread().ident))
print('________________________________')
return 'Check the console! ;-)'
Despite the expectations, threading.current_thread().ident) is never changed, while is id(session._get_current_object() is changing.
session is an object you have imported from the flask module. You only import it once, and it doesn't change, so nor will its id(). It's shared between threads, and it's a proxy to the underlying objects.
Each request may be run on a different thread, and each will have a different underlying object, so they may have different id()s.