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)
Related
I have made a REST API using Python-Flask, now the input for api_call is supposed to be a string and that string needs to have special characters included. The problem occurs here is that when I make the request with http://127.0.0.1:5000/api/<your string>, the browser redirected it as a Google Search Query and sometimes it just throw the Not Found 404 error and this only occurs when I use some special characters in my string like ?. Is there a way to encode the string before calling the api? What I have done is I have made an another program that urlencode the string passed and redirect it to my api call but that doesn't seem like the correct way to call api.
Here's my API code:
# Importing Libraries
from flask import Flask, jsonify, request
# Creating Flask App
app = Flask(__name__)
#app.route('/')
def index():
'''
index function, to inform user of the API route.
params: None
return: None
'''
return f"Visit:<br><strong>{request.url}api/(your string)</strong><br>to get the api response"
#app.route('/api/<string:body>')
def sample(body):
# the code for this function is different and can't be shared but the output works similar
return jsonify({'length': len(body)})
if __name__ == '__main__':
app.run(debug=True)
As I have mentioned the code for the sample() function is different from the original but the output generation is completely similar, the original code is also returning the dictionary which will then be jsonified for response just like the code here. The code for string_reformat is:
# Importing Libraries
from urllib.parse import quote
# URL Encoding String
input_string = input()
print(quote(input_string))
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)
I want to handle a GET request in my Flask REST API. The request will include multiple parameters, and you can expect this to be a typical GET request:
https://localhost:5000/item/analysis=true&class=A&class=B
Thus, a GET request consists of:
a Boolean variable called "analysis"
a list called "class"
I want to accept this inside an add_resource() as follows:
add_resource(Item, '/item/<whatever-comes-here>')
I am clueless about how I would accept multiple parameters (one of them being a list) inside the add_resource(). How do I accept them in the add_resource() function and how do I unpack them inside the get() function?
I have spent time reverse engineering this, but I have not yet been successful. Am I doing something wrong?
(I understand that there might be a better way to send lists with a REST API GET request, so I'd appreciate any pointers regarding that!)
Sincere thanks in advance!
URL parameters are defined after ? so your URL should be instead:
https://localhost:5000/item?analysis=true&class=A&class=B
You don't have to specify anything in add_resource for such URL parameters.
You can just get the parameters from Flask's request proxy object in your API GET method:
from flask import Flask, request
from flask_restful import Api, Resource
app = Flask(__name__)
api = Api(app)
# Flask mishandles boolean as string
TRUTHY = ['true', 'True', 'yes']
class Item(Resource):
def get():
# Get `class` list from request args
classes = request.args.getlist('class')
# Get `analysis` boolean from request args
analysis = True if request.args.get('analysis') in TRUTHY else False
api.add_resource(Item, '/item')
For more flexibility in the parameters you can receive, you can use Flask Restful's own request parser as described here to parse the request.
The code becomes:
from flask import Flask
from flask_restful import Api, Resource, reqparse
app = Flask(__name__)
api = Api(app)
# Define parser and request args
parser = reqparse.RequestParser()
parser.add_argument('class', type=list)
parser.add_argument('analysis', type=bool, default=False, required=False, help='Enable analysis')
class Item(Resource):
def get():
args = parser.parse_args()
classes = args['class'] # List ['A', 'B']
analysis = args['analysis'] # Boolean True
api.add_resource(Item, '/item')
Finally, sometimes a more compact format for a list might be desired (for example limit in url size), in which case I often use a comma separated list:
https://localhost:5000/item?analysis=true&class=A,B
and in the request parser, just accept it like a string and split it on ',':
parser.add_argument('class', type=str)
...
classes = args['class'].split(',')
Cheers !
The query string cannot be use that way.
It will be overwritten, so just use a string such as:
class=A,B
I have a decently intermediate understanding of APIs, and am not trying to host information I've got from APIs onto the web.
This incredibly simple code:
from flask import Flask, request, render_template
import requests
app = Flask(__name__)
#app.route('/temperature', methods=['POST'])
def temperature():
zipcode = request.form['zip']
r = requests.get('http://api.openweathermap.org/data/2.5/weather?zip=' +zipcode+',us&appid=9b56b06ab4c7f06821ccf55e3e10fce5')
json_obj = r.text
return json_obj
#app.route('/')
def index():
return 'hi'
if __name__ == '__main__':
app.run(debug=True)
Is not giving me anything (except the 405 error).
Can someone please explain why my POST method is not working?
While I'm not entirely sure what you have done, here's what I think you did:
You accessed the /temperature page in your browser which is by default a GET-Request.
You then get returned a 405 Method Not Allowed Error, because your route explicitly requires that the page will be accessed via the HTTP-POST Method.
Modify #app.route('/temperature', methods=['POST']) to #app.route('/temperature', methods=['POST', 'GET']) and you should be fine.
I'll post my answer from /r/ flask here, just for posterity.
the line in your code: zipcode = request.form['zip'] implies that you are submitting data from an HTML form to the view via a POST.
If there is no form, then request.form['zip'] does nothing, and is most likely raising the error. Considering that I see no route in your logic there that points to any HTML, I'm guessing that's the issue.
If you have not built a form for the user to submit the zip code, then you could build it into the route logic. For example, you could do:
#app.route('/temperature/<zipcode>')
def temperature(zipcode):
# add some kind of validation here to make sure it's a valid zipcode
r = requests.get('http://api.openweathermap.org/data/2.5/weather?zip=' +zipcode+',us&appid=DONT_SHARE_YOUR_API_KEY')
json_obj = r.text
return json_obj
You could then use http://127.0.0.1:5000/temperature/20003 to see the data for that zip code.
(as a side note, it's often unwise to publicly share your API keys. you may want to generate a new key.)
I'm creating a large number of Flask routes using regular expressions. I'd like to have a unit test that checks that the correct routes exist and that incorrect routes 404.
One way of doing this would be to spin up a local server and use urllib2.urlopen or the like. However, I'd like to be able to run this test on Travis, and I'm assuming that's not an option.
Is there another way for me to test routes on my application?
Use the Flask.test_client() object in your unittests. The method returns a FlaskClient instance (a werkzeug.test.TestClient subclass), making it trivial to test routes.
The result of a call to the TestClient is a Response object, to see if it as 200 or 404 response test the Response.status_code attribute:
with app.test_client() as c:
response = c.get('/some/path/that/exists')
self.assertEquals(response.status_code, 200)
or
with app.test_client() as c:
response = c.get('/some/path/that/doesnt/exist')
self.assertEquals(response.status_code, 404)
See the Testing Flask Applications chapter of the Flask documentation.
Martjin's answer surely solve your issue, but some times you don't have the time (or will) to mock all the components you call in a route you want to test for existence.
And why would you need to mock? Well, the call get('some_route') will first check for this route to exists and then ... it will be executed!
If the view is a complex one and you need to have fixtures, envs variables and any other preparation just for test if the route exists, then you need to think again about your test design.
How to avoid this:
You can list all the routes in your app. An check the one you're testing is in the list.
In the following example, you can see this in practice with the implementation of a site-map.
from flask import Flask, url_for
app = Flask(__name__)
def has_no_empty_params(rule):
defaults = rule.defaults if rule.defaults is not None else ()
arguments = rule.arguments if rule.arguments is not None else ()
return len(defaults) >= len(arguments)
#app.route("/site-map")
def site_map():
links = []
for rule in app.url_map.iter_rules():
# Filter out rules we can't navigate to in a browser
# and rules that require parameters
if "GET" in rule.methods and has_no_empty_params(rule):
url = url_for(rule.endpoint, **(rule.defaults or {}))
links.append((url, rule.endpoint))
# links is now a list of url, endpoint tuples
references:
get a list of all routes defined in the app
Helper to list routes (like Rail's rake routes)
Another way of testing a URL without executing the attached view function is using the method match of MapAdapter.
from flask import Flask
app = Flask(__name__)
#app.route('/users')
def list_users():
return ''
#app.route('/users/<int:id>')
def get_user(id):
return ''
Testing
# Get a new MapAdapter instance. For testing purpose, an empty string is fine
# for the server name.
adapter = app.url_map.bind('')
# This raise werkzeug.exceptions.NotFound.
adapter.match('/unknown')
# This raises werkzeug.exceptions.MethodNotAllowed,
# Although the route exists, the POST method was not defined.
adapter.match('/users', method='POST')
# No exception occurs when there is a match..
adapter.match('/users')
adapter.match('/users/1')
From Werkzeug documentation:
you get a tuple in the form (endpoint, arguments) if there is a match.
Which may be useful in certain testing scenarios.