Flask Get the url variables in a before request? - python

In Flask I have url rules with variables. For example:
my_blueprint.add_url_rule('/<user_token>/bills/',view_func=BillsView.as_view('bills'))
This is going to pass the user_token variable to the BillsView's get and post methods.
I am trying to intercept that user_token variable in the before_request of my blueprint.
Here is my blueprint before_request:
def before_req():
...
...
my_blueprint.before_request(before_req)
The closest I have come is to use request.url_rule. But that does not give me the content of the variable. Just the rule that matches.

Register a URL processor using #app.url_value_preprocessor, which takes the endpoint and values matched from the URL. The values dict can be modified, such as popping a value that won't be used as a view function argument, and instead storing it in the g namespace.
from flask import g
#app.url_value_preprocessor
def store_user_token(endpoint, values):
g.user_token = values.pop('user_token', None)
The docs include a detailed example of using this for extracting an internationalization language code from the URL.

Apart from the URL preprocessors as described above, another approach to get args passed to the URL explicitly will be to use this.
#app.before_request
def get_request_args():
"Provides all request args"
request_args = {**request.view_args, **request.args} if request.view_args else {**request.args}
print('All Request args ',request_args)
More info in the documentation of request.args and request.view_args

Related

Python Flask: How to implement multiple URL redirects in bulk?

I am aware of Flask's redirect(<URL>) function that I can use inside routes.
But I have dozens of URLs that I need to redirect to a different website. I was wondering if there is a way I can implement redirects without writing multiple redirect(<URL>) statements across many blueprints and routes.
I was wondering if I could just supply Flask with my redirect mapping data in bulk. e.g.
www.example.com/example-1 => subdomain.example.com/example-1
www.example.com/example-2 => subdomain.example.com/example-2
www.example.com/example-3 => subdomain.example.com/example-3
Yes, you can do redirects with dictionaries or a list of tuples to hold them.
For example:
from flask import Flask, redirect
app = Flask(__name__)
# Define a dictionary of redirect mappings
redirects = {
"/example-1": "http://subdomain.example.com/example-1",
"/example-2": "http://subdomain.example.com/example-2",
"/example-3": "http://subdomain.example.com/example-3"
}
# Register a route to handle all the redirects
#app.route('/<path:path>')
def redirect_to_new_url(path):
if path in redirects:
new_url = redirects[path]
return redirect(new_url, code=302)
else:
return "Page not found", 404
if __name__ == '__main__':
app.run(debug=True)
cheesecake87 from Reddit provided this solution, which I will mark as accepted answer.
from flask import request
#app.before_request
def before_request():
redir = (
('https://www.example.com/example-1', 'https://subdomain.example.com/example-1'),
('https://www.example.com/example-2', 'https://subdomain.example.com/example-2')
)
for v in redir:
if request.url in v[0]:
return redirect(v[1], code=302)
Source 1: https://www.reddit.com/r/flask/comments/115sdhm/comment/j95q9va/?utm_source=share&utm_medium=web2x&context=3
Source 2: https://stackoverflow.com/a/16121323
Hack-R's solution was good. But redirection URL rule was sorted to be at the very bottom of the URL rules list (by Werkzeug), so the redirection didn't take place unless I removed the original routes that I wanted redirected.
With this solution, URLs are evaluated BEFORE it reaches the URL rule list.

flask redirecting with url and api key required

I have two endpoints and I'd like to redirect from one to the other. Both require the same api key:
#blueprint.route("v1/method/<param>", methods=["PUT"])
#api_key_required
#write_required(api=True)
def method(param):
return redirect(url_for('v2.method', param=param), code=307)
#blueprint.route("v2/method/<param>", methods=["PUT"])
#api_key_required
#write_required(api=True)
def method(param):
#handle the request
redirection seems to work fine but it looks like api_key is not passed. I receive unauthorised status. What should I do?
I found the solution. request.args need to be pass as additional arguments. So the correct code is:
return redirect(url_for('v2.method', param=param, **request.args), code=307)

Redirecting with updated requests parameters

I write grid filters and some functionality is not implemented yet, so I want to redirect people to default grid when they try to use the unimplemented features. In my controller I have access to a request object. Can I update its parameters and use my request object, to redirect the user?
I tried to update request.params directly but it's a read-only object. Tried to use httpfound but it doesn't accept params.
try:
self._parse_filters(filters)
except NotImplementedError:
url = self.request.route_
self.reset_filters = True
self.error = 'Not Implemented Functionality. Default filters loaded'
self._parse_filters(self.default_filters)
You need to build a new URL (possibly based on the parameters in your current request) and use HTTPFound to generate a redirect. To generate the query part of your new url you can use _query parameter of request.route_url method or simply use urllib.urlencode.
new_url = request.route_url(
'not_implemented_view',
blah='boo',
_query={'sort':'asc'} # you can give it request.GET if you want all the same url parameters
)
return HttpFound(new_url)

send data while redirect to view in django

Is it possible to send data while to redirecting to another view?
For example:-
def social_user():
//do something here
return redirect('name of the view',{'variable':'value'})
or any other alternative to exchange data between a function and view function.
There are two ways to send data to the resulting destination, but first you should understand how redirects work.
When the server redirects, it just sets the Location header telling the browser which page to fetch next.
Location: /foo.html
Since the body is completely ignored even if present, you must somehow pass data via the HTTP headers.
1) Query Parameters
The easiest way is to use query (GET) parameters which you can then read from the destination page:
Location: /foo.html?username=bob
The downside is that the user can easily see and modify this value.
2) Cookies
The session, which is determined by cookies, is another place to store temporary data. But this has several downsides:
It is not tied to any request, so you all consequent request will have access to the data until you delete it.
It doesn't work if the user has disabled cookies. On the other hand query parameters always work.
If you choose the first option, you may need to write some of your own code since Django doesn't seem to offer a convenient method to do this (someone correct me if I'm wrong). Here's a sample function that wraps the functionality:
def redirect_with_query(path, query=None, *args, **kwargs):
if query is None:
query = {}
url = resolve_url(path, *args, **kwargs)
if len(query):
q_dict = QueryDict(mutable=True)
q_dict.update(query)
url += '?' + q_dict.urlencode()
return HttpResponseRedirect(url)
First Solution::
If you have access to the request variable in social_user, you can simply make use of sessions. Sessions are the best way to transfer data between 2 views.
def social_user(request):
request.session['variable'] = 'value'
return redirect('name of the view')
Then inside your view, you can access this variable using request.session.get('variable')
Second Solution::
In case you can't set session variables, send them as query parameters.
def social_user():
//do something here
return redirect("your_view/?variable=value")
Build a "mock django request" manually and call the view directly
Use query parameters
Use render() and pass the variable via context:
def social_user(request)
// do something here
return render(request, template_name='template.html', context={'variable': 'value'})

How do you access the query string in Flask routes?

How do you access query parameters or the query string in Flask routes? It's not obvious from the Flask documentation.
The example route /data below illustrates the context that I would like to access that data. If someone requests something like example.com/data?abc=123, I would like access to the string ?abc=123 or to be able to retrieve the value of parameters like abc.
#app.route("/data")
def data():
# query_string = ???
return render_template("data.html")
from flask import request
#app.route('/data')
def data():
# here we want to get the value of user (i.e. ?user=some-value)
user = request.args.get('user')
The full URL is available as request.url, and the query string is available as request.query_string.decode().
Here's an example:
from flask import request
#app.route('/adhoc_test/')
def adhoc_test():
return request.query_string
To access an individual known param passed in the query string, you can use request.args.get('param'). This is the "right" way to do it, as far as I know.
ETA: Before you go further, you should ask yourself why you want the query string. I've never had to pull in the raw string - Flask has mechanisms for accessing it in an abstracted way. You should use those unless you have a compelling reason not to.
I came here looking for the query string, not how to get values from the query string.
request.query_string returns the URL parameters as raw byte string (Ref 1).
Example of using request.query_string:
from flask import Flask, request
app = Flask(__name__)
#app.route('/data', methods=['GET'])
def get_query_string():
return request.query_string
if __name__ == '__main__':
app.run(debug=True)
Output:
References:
Official API documentation on query_string
We can do this by using request.query_string.
Example:
Lets consider view.py
from my_script import get_url_params
#app.route('/web_url/', methods=('get', 'post'))
def get_url_params_index():
return Response(get_url_params())
You also make it more modular by using Flask Blueprints - https://flask.palletsprojects.com/en/1.1.x/blueprints/
Lets consider first name is being passed as a part of query string
/web_url/?first_name=john
## here is my_script.py
## import required flask packages
from flask import request
def get_url_params():
## you might further need to format the URL params through escape.
firstName = request.args.get('first_name')
return firstName
As you see this is just a small example - you can fetch multiple values + formate those and use it or pass it onto the template file.
Werkzeug/Flask as already parsed everything for you. No need to do the same work again with urlparse:
from flask import request
#app.route('/')
#app.route('/data')
def data():
query_string = request.query_string ## There is it
return render_template("data.html")
The full documentation for the request and response objects is in Werkzeug: http://werkzeug.pocoo.org/docs/wrappers/
Try like this for query string:
from flask import Flask, request
app = Flask(__name__)
#app.route('/parameters', methods=['GET'])
def query_strings():
args1 = request.args['args1']
args2 = request.args['args2']
args3 = request.args['args3']
return '''<h1>The Query String are...{}:{}:{}</h1>''' .format(args1,args2,args3)
if __name__ == '__main__':
app.run(debug=True)
Output:
Every form of the query string retrievable from flask request object as described in O'Reilly Flask Web Devleopment:
From O'Reilly Flask Web Development, and as stated by Manan Gouhari earlier, first you need to import request:
from flask import request
request is an object exposed by Flask as a context variable named (you guessed it) request. As its name suggests, it contains all the information that the client included in the HTTP request. This object has many attributes and methods that you can retrieve and call, respectively.
You have quite a few request attributes which contain the query string from which to choose. Here I will list every attribute that contains in any way the query string, as well as a description from the O'Reilly book of that attribute.
First there is args which is "a dictionary with all the arguments passed in the query string of the URL." So if you want the query string parsed into a dictionary, you'd do something like this:
from flask import request
#app.route('/'):
queryStringDict = request.args
(As others have pointed out, you can also use .get('<arg_name>') to get a specific value from the dictionary)
Then, there is the form attribute, which does not contain the query string, but which is included in part of another attribute that does include the query string which I will list momentarily. First, though, form is "A dictionary with all the form fields submitted with the request." I say that to say this: there is another dictionary attribute available in the flask request object called values. values is "A dictionary that combines the values in form and args." Retrieving that would look something like this:
from flask import request
#app.route('/'):
formFieldsAndQueryStringDict = request.values
(Again, use .get('<arg_name>') to get a specific item out of the dictionary)
Another option is query_string which is "The query string portion of the URL, as a raw binary value." Example of that:
from flask import request
#app.route('/'):
queryStringRaw = request.query_string
Then as an added bonus there is full_path which is "The path and query string portions of the URL." Por ejemplo:
from flask import request
#app.route('/'):
pathWithQueryString = request.full_path
And finally, url, "The complete URL requested by the client" (which includes the query string):
from flask import request
#app.route('/'):
pathWithQueryString = request.url
Happy hacking :)
I prefer
user = request.args['user'] if 'user' in request.args else 'guest'
over
user = request.args.get('user')
this way, you can check the url actually contains the query string first
The implementation below worked for me.
from flask import request
def getVerificationStatus():
try:
requestId=int(request.args.get('requestId'))
print(requestId)
status= verificationStepRepository.getVerificationStatus(requestId)
return tb.responsify(200, "success", status)
except Exception as e:
return errorHandler.dispatchInternalServerError(str(e))
Often we just want to map the whole query string into an appropriate python data structure and take it from there. The appropriate structure is a multi-dictionary because keywords can repeat, for example we need to handle A=123&A=456&B=789. A multi-dictionary is a list of 2-tuples where each 2-tuple contains the key as its first item and the list of values as its second, so the above goes to [('A',['123','456']),('B',['789'])]. All of this is achieved by
qstr = request.args.lists() # A generator for the multi-dict
qstr = list(qstr) # To get the actual multi-dict
If all you want is a dictionary where the first occurrence of a duplicate keyword is used you can just go
qstr = request.args.to_dict()
This can be done using request.args.get().
For example if your query string has a field date, it can be accessed using
date = request.args.get('date')
Don't forget to add "request" to list of imports from flask,
i.e.
from flask import request
If the request if GET and we passed some query parameters then,
fro`enter code here`m flask import request
#app.route('/')
#app.route('/data')
def data():
if request.method == 'GET':
# Get the parameters by key
arg1 = request.args.get('arg1')
arg2 = request.args.get('arg2')
# Generate the query string
query_string="?arg1={0}&arg2={1}".format(arg1, arg2)
return render_template("data.html", query_string=query_string)
This Code worked for me:
from flask import Flask, request
app = Flask(__name__)
#app.route('/')
def search():
query = request.args
for key,value in query.items():
print(key,value)
return "Hello World"
if __name__ == '__main__':
app.run(debug=True)

Categories