I looked at the code for CreateAPIView and nowhere in the creation process are permissions checked. So I decided to check them in the perform_create
hook as follows:
class CourseList(generics.CreateAPIView):
"""
Create a course.
A user can create a course if he/she is an instructor in
the academy the course is to be created in.
"""
serializer_class = CourseRef
queryset = Course.objects.all()
permission_classes = (IsAuthenticated, IsInstructorInAcademy)
def perform_create(self, serializer):
self.check_object_permissions(self.request, serializer.validated_data.get('academy'))
serializer.save()
where the permission looks like:
class IsInstructorInAcademy(BasePermission):
def has_object_permission(self, request, view, academy):
return request.user.instructor_set.filter(academy=academy).exists()
When I try to create a course, the initial permission check runs fine and the course is saved but immediately afterwards I get the following error:
ValueError at /api/courses/
Cannot query "Mathematics 11A": Must be "Academy" instance.
and this is raised at the permissions check, as a result of which the POST returns a 500 ISE.
(This is slightly hacky because I'm passing in the academy instance in the permissions check in the perform_create
hook whereas the view really concerns courses. I considered using a permission IsInstructorInAcademyOfObject
but for that, I would need to pass in an object which I cannot get unless the serializer is saved.)
What is the best way to check for permissions here?
You have an issue because you're tying business logic checks with permissions.
Instead of calling
check_object_permission
, perform your own check once it's deserialized and raise aPermissionDenied
if it fails.