Python flask not working with url containing "?"
Question:
I am new to flask and I was trying to make GET request for url containing "?" symbol but it look like my program is just skipping work with it. I am working with flask-sql alchemy, flask and flask-restful. Some simplified look of my program looks like this:
fields_list = ['id']
db = SQLAlchemy(app)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
class Get(Resource):
@staticmethod
def get():
users = User.query.all()
usr_list = Collection.user_to_json(users)
return {"Users": usr_list}, 200
class GetSorted(Resource):
@staticmethod
def get(field, type):
if field not in fields_list or type not in ['acs', 'desc']:
return {'Error': 'Wrong field or sort type'}, 400
users = db.session.execute(f"SELECT * FROM USER ORDER BY {field} {type}")
usr_list = Collection.user_to_json(users)
return {"Users": usr_list}, 200
api.add_resource(GetSorted, '/api/customers?sort=<field>&sort_type=<type>')
api.add_resource(Get, '/api/customers')
Output with url "http://127.0.0.1:5000/api/customers?sort=id&sort_type=desc" looks like this
{
"Users": [
{
"Id": 1
},
{
"Id": 2
},
{
"Id": 3
},
]
}
But I expect it to look like this
{
"Users": [
{
"Id": 3
},
{
"Id": 2
},
{
"Id": 1
},
]
}
Somehow if I replace "?" with "/" in url everything worked fine, but I want it to work with "?"
Answers:
In order to get the information after ?, you have to use request.args. This information is Query Parameters, which are part of the Query String: a section of the URL that contains key-value parameters.
If your route is:
api.add_resource(GetSorted, '/api/customers?sort=<field>&sort_type=<type>')
Your key-values would be:
sort=<field>
sort_type=<type>
And you could get the values of the field and type keys like this:
sort = request.args.get('field', 'field_defaul_value')
sort_type = request.args.get('type', 'type_defaul_value')
More info:
With Flask you can define path variables like you did, but they must be part of the path. For example, defining a path of /api/customers/<id>
can be used to get a specific customer by id, defining the function as def get(id):
. Query parameters cannot be defined in such a way, and as you mentioned in your comment, you need to somehow "overload" the get function. Here is one way to do it:
from flask import Flask, request
from flask_restful import Resource, Api
app = Flask(__name__)
api = Api(app)
USERS = [
{"id": 1},
{"id": 3},
{"id": 2},
]
class Get(Resource):
@classmethod
def get(cls):
if request.args:
return cls._sorted_get()
return {"Users": USERS, "args":request.args}, 200
@classmethod
def _sorted_get(cls):
field = request.args.get("sort")
type = request.args.get("sort_type")
if field not in ("id",) or type not in ['acs', 'desc']:
return {'Error': 'Wrong field or sort type'}, 400
sorted_users = sorted(USERS, key=lambda x: x[field], reverse=type=="desc")
return {"Users": sorted_users}, 200
api.add_resource(Get, '/api/customers')
if __name__ == '__main__':
app.run(debug=True)
Here is Flask’s documentation regarding accessing request data, and Flask-Restful’s quickstart guide.
I am new to flask and I was trying to make GET request for url containing "?" symbol but it look like my program is just skipping work with it. I am working with flask-sql alchemy, flask and flask-restful. Some simplified look of my program looks like this:
fields_list = ['id']
db = SQLAlchemy(app)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
class Get(Resource):
@staticmethod
def get():
users = User.query.all()
usr_list = Collection.user_to_json(users)
return {"Users": usr_list}, 200
class GetSorted(Resource):
@staticmethod
def get(field, type):
if field not in fields_list or type not in ['acs', 'desc']:
return {'Error': 'Wrong field or sort type'}, 400
users = db.session.execute(f"SELECT * FROM USER ORDER BY {field} {type}")
usr_list = Collection.user_to_json(users)
return {"Users": usr_list}, 200
api.add_resource(GetSorted, '/api/customers?sort=<field>&sort_type=<type>')
api.add_resource(Get, '/api/customers')
Output with url "http://127.0.0.1:5000/api/customers?sort=id&sort_type=desc" looks like this
{
"Users": [
{
"Id": 1
},
{
"Id": 2
},
{
"Id": 3
},
]
}
But I expect it to look like this
{
"Users": [
{
"Id": 3
},
{
"Id": 2
},
{
"Id": 1
},
]
}
Somehow if I replace "?" with "/" in url everything worked fine, but I want it to work with "?"
In order to get the information after ?, you have to use request.args. This information is Query Parameters, which are part of the Query String: a section of the URL that contains key-value parameters.
If your route is:
api.add_resource(GetSorted, '/api/customers?sort=<field>&sort_type=<type>')
Your key-values would be:
sort=<field>
sort_type=<type>
And you could get the values of the field and type keys like this:
sort = request.args.get('field', 'field_defaul_value')
sort_type = request.args.get('type', 'type_defaul_value')
More info:
With Flask you can define path variables like you did, but they must be part of the path. For example, defining a path of /api/customers/<id>
can be used to get a specific customer by id, defining the function as def get(id):
. Query parameters cannot be defined in such a way, and as you mentioned in your comment, you need to somehow "overload" the get function. Here is one way to do it:
from flask import Flask, request
from flask_restful import Resource, Api
app = Flask(__name__)
api = Api(app)
USERS = [
{"id": 1},
{"id": 3},
{"id": 2},
]
class Get(Resource):
@classmethod
def get(cls):
if request.args:
return cls._sorted_get()
return {"Users": USERS, "args":request.args}, 200
@classmethod
def _sorted_get(cls):
field = request.args.get("sort")
type = request.args.get("sort_type")
if field not in ("id",) or type not in ['acs', 'desc']:
return {'Error': 'Wrong field or sort type'}, 400
sorted_users = sorted(USERS, key=lambda x: x[field], reverse=type=="desc")
return {"Users": sorted_users}, 200
api.add_resource(Get, '/api/customers')
if __name__ == '__main__':
app.run(debug=True)
Here is Flask’s documentation regarding accessing request data, and Flask-Restful’s quickstart guide.