I have this url route, can I get user_id with flask.request?
I want to create a wrapper, and get the user_id here.
def test_required(fn):
#wraps(fn)
def wrapper(*args, **kwargs):
user_id = ?????
return fn(*args, **kwargs)
return wrapper
#app.route('/api/test/<int:user_id>', methods=['GET'])
#test_required
def jwt_routes_test(user_id):
request.args, request.form, or request.values not return this value.
Can I access it somehow?
This code is only valid with a view function that accepts user_id as an argument. So, you simply get it from there.
Use it as a parameter in your route:
#app.route('/api/test/<int:user_id>', methods=['GET'])
def myroute(user_id: int):
# do something
https://flask.palletsprojects.com/en/1.0.x/quickstart/#variable-rules
Looks like you're asking for view_args dictionary.
A dict of view arguments that matched the request. If an exception
happened when matching, this will be None.
Related
I'm working on flask RESTful application that uses auth0 for authentication and authorization. Then, I wrote a decorator that validates the token and extract user's id from it. My goal is use that id, extracted from token, to used inside the decorated function, and throw an exception if user's id from token and from URL parameter doesn't match. This is aimed to avoid users to change data of another user, with his own token. I'm not sure this is the best practice for a RESTful app, but seems to be needed in my case.
That said, I trying to figure out the best approach pass the user's id from token, to the decorated funcion:
Something like this:
def authorization():
def inner(func):
def wrapper(*args, **kwargs):
try:
"""
token validation stuff
...
"""
wrapper.user_id = token_payload['user_id']
except Exception:
return {"success": False}, 500
return func(*args, **kwargs)
return wrapper
return inner
#authorization()
#app.route('/test', methods=['GET'])
def some_function():
return jsonify({
'success': True,
'user_id': some_function.user_id
})
As you can see, I setting the user_id field to the wrapper function, which seems to not be the best way, to do it. Is there any different approach to this situation? maybe using Flask resources?
You can skip one level of wrapping in your decorator since you're not giving it any parameters.
Also, I'd just pass the extracted id into the wrapped function directly instead of setting an attribute.
And finally, you should add the auth decorater innermost, since the decorated function is what you want to register with Flask.
Extra: use functools.wraps to update the signature of your wrapped function, to make introspection and debugging easier.
Thus:
from functools import wraps
def authorized(func):
#wraps(func)
def wrapper(*args, **kw):
try:
# token stuff
user_id = token_payload['user_id']
except:
return jsonify({"success": False}), 500
return func(user_id, *args, **kw)
return wrapper
#app.route('/test', methods=['GET'])
#authorized
def some_function(user_id):
return jsonify({
'success': True,
'user_id': user_id
})
Now every function you decorate with #authorized will need to have user_id as their first parameter, and everything should work as you expect.
Is there any chances to specify which parameters are required in url query and automatically pass them into view function?
In urls.py I would like to have something like this:
path('get_part_info?<part>', views.get_part_info, name='get_part_info'),
And in views.py to have something like this:
def get_part_info(request, part):
# do something with part
return JsonResponse({'result': part})
Idea is to avoid ugly construction like: part= request.GET.get('part')
URL path is not a solution, because "part" value can have various extra characters like slashes etc.
You can write a decorator:
from functools import wraps
from django.http import HttpResponseBadRequest, JsonResponse
def query_params(*param_names):
def decorator(func):
#wraps(func)
def inner(request, *args, **kwargs):
try:
params = {name: request.GET[name] for name in param_names}
except KeyError:
return HttpResponseBadRequest("Missing Parameter")
kwargs.update(params)
return func(request, *args, **kwargs)
return inner
return decorator
#query_params("part")
def get_part_info(request, part):
# do something with part
return JsonResponse({"result": part})
This decorator returns a 400 if a parameter is missing, but that could be changed any way you want, for example, redirect to another URL or to use default values.
I've seen the posts on passing GET parameters and hardcoded parameters here and here.
What I am trying to do is pass POST parameters to a custom decorator. The route is not actually rendering a page but rather processing some stuff and sending the results back through an AJAX call.
The decorator looks like this:
# app/util.py
from functools import wraps
from models import data
# custom decorator to validate symbol
def symbol_valid():
def decorator(func):
#wraps(func)
def decorated_function(symbol, *args, **kwargs):
if not data.validate_symbol(symbol):
return jsonify({'status': 'fail'})
return func(*args, **kwargs)
return decorated_function
return decorator
The view looks something like this:
# app/views/matrix_blueprint.py
from flask import Blueprint, request, jsonify
from ..models import data
from ..util import symbol_valid
matrix_blueprint = Blueprint('matrix_blueprint', __name__)
# routing for the ajax call to return symbol details
#matrix_blueprint.route('/route_line', methods=['POST'])
#symbol_valid
def route_line():
symbol = request.form['symbol'].upper()
result = data.get_information(symbol)
return jsonify(**result)
I understand that I can actually call #symbol_valid() when I pass a parameter through GET like this /quote_line/<symbol> but I need to POST.
The question then is how can my decorator access the POSTed variable?
Simple solution. Imported Flask's request module into the util.py module which contains the decorator. Removed the outer function as well.
See code:
# app/util.py
from flask import request # <- added
from functools import wraps
from models import data
# custom decorator to validate symbol
def symbol_valid(func):
#wraps(func)
def decorated_function(*args, **kwargs): # <- removed symbol arg
symbol = request.form['symbol'] # <- paramter is in the request object
if not data.validate_symbol(symbol):
return jsonify({'status': 'fail'})
return func(*args, **kwargs)
return symbol_valid
The decorator accept a func parameter. You must use your decorator like #symbol_valid() or make the function symbol_valid accept a func parameter.
If you are doing it right, you can access the request object anywhere during the request cycle. It just works.
I want my authorization decorator to be able to pass a custom user object to the view that it decorates.
Currently, I am having the decorator set an attribute on flask.g to do this. Is this acceptable use of flask.g or is there a better way?
My code looks something like this:
def auth(f):
#wraps(f):
def decorated(*args, **kwargs):
user = getUserObj(request.headers.get('user'), request.headers.get('pass'))
flask.g.user = user
return f(*args, **kwargs)
return decorated
And then the view is:
#api.route('/info')
#auth
def info():
flask.g.user # this contains my user object now
Iam using django decorators in my project.
Iam using multiple views with arguments and i need to call 1 decorator.
I want only one view to call with its arguments once. But the decorators giving the values of every views wherever i used the decorator.
I want the argument belong to the particular views which i called.
My views and decorator as:
def d(msg='my default message'):
def decorator(func):
print msg
def newfn(request, **kwargs):
return func(request, **kwargs)
return newfn
return decorator
#d('This is working')
def company_add(request):
return ...
#d('Dont come')
def company_list(request, comp_id = None):
return ...
If i call company_add views, Iam getting Output as :
This is working
Dont come
But my expected result is
This is working.
Anyone help me to print only the argument belong to the particular views.
When you wrap function with #d(arg), you actually run the body of the d function with msg=arg before running decorated function and of course print the msg. You can place the print statement somewhere else, for example:
def d(msg='my default message'):
def decorator(func):
def newfn(request, **kwargs):
print msg
return func(request, **kwargs)
return newfn
return decorator
The solution is to move print msg to the scope of the newfn wrapper. When you call the decorator with an argument specified, it executes and results in the behavior described above.
def d(msg='my default message'):
def decorator(func):
def newfn(request, **kwargs):
print msg # The message should be printed here.
return func(request, **kwargs)
return newfn
return decorator