I have created a decorator in my Django project to inject parameter values to the decorated method's parameters.
I do this by using inspect.getargspec
to check which parameters are present in the method and place them in kwargs
. Otherwise I get an error due to the incorrect number of parameters in the method.
While this works properly in individual view methods, it fails when it comes to Django's class based views.
I believe this might be because the decorators are applied using @method_decorator
at the class level to the dispatch
method instead of the individual get
and post
methods.
I'm a python newbie and might be overlooking something obvious here.
Is there a better way to do what I'm doing? Is it possible to get the method parameter names in a class based view?
I'm using Python 2.7 and Django 1.11
The Decorator
def need_jwt_verification(decorated_function):
@wraps(decorated_function)
def decorator(*args, **kwargs):
request = args[0]
if not isinstance(request, HttpRequest):
raise RuntimeError(
"This decorator can only work with django view methods accepting a HTTPRequest as the first parameter")
if AUTHORIZATION_HEADER_NAME not in request.META:
return HttpResponse("Missing authentication header", status=401)
jwt_token = request.META[AUTHORIZATION_HEADER_NAME].replace(BEARER_METHOD_TEXT, "")
try:
decoded_payload = jwt_service.verify_token(jwt_token)
parameter_names = inspect.getargspec(decorated_function).args
if "phone_number" in parameter_names or "phone_number" in parameter_names:
kwargs["phone_number"] = decoded_payload["phone"]
if "user_id" in parameter_names:
kwargs["user_id"] = decoded_payload["user_id"]
if "email" in parameter_names:
kwargs["email"] = decoded_payload["email"]
return decorated_function(*args, **kwargs)
except JWTError as e:
return HttpResponse("Incorrect or expired authentication header", status=401)
return decorator
A class based view
@method_decorator([csrf_exempt, need_jwt_verification], name="dispatch")
class EMController(View):
def get(self, request, phone_number, event_id):
data = get_data()
return JsonResponse(data, safe=False)
def post(self, request, phone_number, event_id):
return JsonResponse("Operation successful", safe=False)
EDIT:
The obvious solution of applying the decorator at the method level, doesn't work with Django's class based views. You need apply the decorator at the url configuration or apply the decorator to the dispatch method.
EDIT: I've posted code that was related to a workaround I was exploring, passing the parameter names as an argument into the decorator.