Reputation: 1249
I use Django Rest Framework to build my API and it works fine. I use function based views to manage my endpoints. It works well too but I'm trying to add a custom permission class and putting parameters with it do not work.
An example of one of my endpoints :
@api_view(http_method_names=["GET"])
@permission_classes([IsAuthenticated])
def team_kanban(request):
"""
List all Helpdesk Teams with kanban fields.
"""
teams = HelpdeskTeam.objects.all()
return Response(HelpdeskTeamKanbanSerializer(teams, many=True).data)
It works without any problem. But when I try to do :
@api_view(http_method_names=["GET"])
@permission_classes([IsAuthenticated, HasPermission("view_helpdeskteam")])
def team_kanban(request):
"""
List all Helpdesk Teams with kanban fields.
"""
teams = HelpdeskTeam.objects.all()
return Response(HelpdeskTeamKanbanSerializer(teams, many=True).data)
with this custom permission class :
from rest_framework import permissions
class HasPermission(permissions.BasePermission):
"""
Allows access only to users who have the appropriate permission.
"""
permission_codename = ""
def __init__(self, permission_codename):
super().__init__()
self.permission_codename = permission_codename
def has_permission(self, request, view):
return request.user.has_permission(self.permission_codename)
It doesn't work. The full error is :
Traceback (most recent call last):
File "C:\Program Files\Python37\lib\site-packages\django\core\handlers\exception.py", line 47, in inner
response = get_response(request)
File "C:\Program Files\Python37\lib\site-packages\django\core\handlers\base.py", line 181, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:\Program Files\Python37\lib\site-packages\django\views\decorators\csrf.py", line 54, in wrapped_view
return view_func(*args, **kwargs)
File "C:\Program Files\Python37\lib\site-packages\django\views\generic\base.py", line 70, in view
return self.dispatch(request, *args, **kwargs)
File "C:\Program Files\Python37\lib\site-packages\rest_framework\views.py", line 509, in dispatch
response = self.handle_exception(exc)
File "C:\Program Files\Python37\lib\site-packages\rest_framework\views.py", line 469, in handle_exception
self.raise_uncaught_exception(exc)
File "C:\Program Files\Python37\lib\site-packages\rest_framework\views.py", line 480, in raise_uncaught_exception
raise exc
File "C:\Program Files\Python37\lib\site-packages\rest_framework\views.py", line 497, in dispatch
self.initial(request, *args, **kwargs)
File "C:\Program Files\Python37\lib\site-packages\rest_framework\views.py", line 415, in initial
self.check_permissions(request)
File "C:\Program Files\Python37\lib\site-packages\rest_framework\views.py", line 331, in check_permissions
for permission in self.get_permissions():
File "C:\Program Files\Python37\lib\site-packages\rest_framework\views.py", line 278, in get_permissions
return [permission() for permission in self.permission_classes]
File "C:\Program Files\Python37\lib\site-packages\rest_framework\views.py", line 278, in <listcomp>
return [permission() for permission in self.permission_classes]
TypeError: 'HasPermission' object is not callable
It seems my class is not callable with the parameter.
How can I achieve this ?
Thanks in advance :)
Upvotes: 3
Views: 2311
Reputation: 32304
permission_classes
must be passed a list of permission classes, not instances of permissions. One way to dynamically create permission classes would be to create a method that returns a dynamically created class using type
from rest_framework import permissions
class HasPermissionBase(permissions.BasePermission):
"""
Allows access only to users who have the appropriate permission.
"""
permission_codename = ""
def has_permission(self, request, view):
return request.user.has_permission(self.permission_codename)
def HasPermission(permission_codename):
return type('HasPermission', (HasPermissionBase, ), {'permission_codename': permission_codename})
Or you could override the __call__
method on your custom permission and return self
so that it acts like a class when called
class HasPermission(permissions.BasePermission):
"""
Allows access only to users who have the appropriate permission.
"""
permission_codename = ""
def __init__(self, permission_codename):
super().__init__()
self.permission_codename = permission_codename
def __call__(self):
return self
def has_permission(self, request, view):
return request.user.has_permission(self.permission_codename)
Upvotes: 6