I figured it out: It's a bug in Django REST Framework JSON API. I found a 
workaround by specifying a resource name on my view, which avoids the call 
to self.get_object() and in turn avoids the permission check.

Thanks,
Kevin

On Saturday, November 14, 2020 at 2:29:06 PM UTC-6 Kevin Partington wrote:

> I've created a special permission class which checks that the current user 
> is either accessing the resource readonly, or is an admin user, or is a 
> specific user according to a different property on the object.
>
> When I try to view the resource on the browsable API, I get a permission 
> denied error. Strangely, when I looked at request.method in the permission 
> class at the time of the exception, I was seeing POST rather than GET. I 
> debugged using pdb and saw that the view was basically being called twice-- 
> once with request.method == GET, once with request.method == POST. The 
> second permission check throws an exception which breaks the page.
>
> According to the pdb listings, the reason this happens is the response 
> template needs to be able to render a POST, PUT, and PATCH form. It seems 
> it might be calling the request again in order to see what the resource 
> "shape" is, and/or to double check permissions. But it seems strange that 
> the exception is allowed to go all the way through rather than being caught 
> in that template (and maybe choosing not to render the form for users who 
> have GET permission but not POST permission).
>
> I have to assume this isn't the intentional design, and I might be 
> accidentally tripping something up with some of the renderers etc. I am 
> using. I am using DRF and also the Django REST Framework JSON API library.
>
> My views:
>
> class JamSessionRelationshipView(RelationshipView):
>     queryset = JamSession.objects.all()
>
> class JamSessionMembersRelationshipView(JamSessionRelationshipView):
>     permission_classes = [IsConductorOrAdminOrReadOnly]
>
> My permission class:
>
> class IsConductorOrAdminOrReadOnly(permissions.BasePermission):
>     message = "User must be an admin or conductor to modify the jam 
> session members."
>
>     def has_object_permission(self, request, view, obj):
>         if request.method in permissions.SAFE_METHODS:
>             return True
>
>         if request.user.is_staff:
>             return True
>
>         return request.user == obj.conductor
>
> My DRF settings:
>
> REST_FRAMEWORK = {
>     'PAGE_SIZE': 10,
>     'EXCEPTION_HANDLER': 
> 'rest_framework_json_api.exceptions.exception_handler',
>     'DEFAULT_PERMISSION_CLASSES': [
>         'rest_framework.permissions.IsAuthenticatedOrReadOnly',
>     ],
>     'DEFAULT_PAGINATION_CLASS':
>         'rest_framework_json_api.pagination.JsonApiLimitOffsetPagination',
>     'DEFAULT_PARSER_CLASSES': (
>         'rest_framework_json_api.parsers.JSONParser',
>         'rest_framework.parsers.FormParser',
>         'rest_framework.parsers.MultiPartParser'
>     ),
>     'DEFAULT_RENDERER_CLASSES': (
>         'rest_framework_json_api.renderers.JSONRenderer',
>         # If you're performance testing, you will want to use the 
> browseable API
>         # without forms, as the forms can generate their own queries.
>         # If performance testing, enable:
>         # 'example.utils.BrowsableAPIRendererWithoutForms',
>         # Otherwise, to play around with the browseable API, enable:
>         'rest_framework.renderers.BrowsableAPIRenderer'
>     ),
>     'DEFAULT_METADATA_CLASS': 
> 'rest_framework_json_api.metadata.JSONAPIMetadata',
>     'DEFAULT_FILTER_BACKENDS': (
>         'rest_framework_json_api.filters.QueryParameterValidationFilter',
>         'rest_framework_json_api.filters.OrderingFilter',
>         #'rest_framework_json_api.django_filters.DjangoFilterBackend',
>         'rest_framework.filters.SearchFilter',
>     ),
>     'SEARCH_PARAM': 'filter[search]',
>     'TEST_REQUEST_RENDERER_CLASSES': (
>         'rest_framework_json_api.renderers.JSONRenderer',
>     ),
>     'TEST_REQUEST_DEFAULT_FORMAT': 'vnd.api+json',
> }
>
> Please let me know if I can provide any other helpful information.
>
> Thanks,
> Kevin
>

-- 
You received this message because you are subscribed to the Google Groups 
"Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-rest-framework+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-rest-framework/54bdd00a-68a0-4356-a828-fb6349034fc7n%40googlegroups.com.

Reply via email to