4

I have a simple DRF list view and wanted to write some permissions pertaining to POST requests. That resulted in an error when GET requests were issued. That led me to realize that my permission class is being called multiple times on requests that were not submitted. Here are my files.

permissons.py:

class IsDummy(permissions.BasePermission):
    def has_permission(self, request, view):
        print("\n{}\n".format(request.method)) 
        if request.method in permissions.SAFE_METHODS:
            return True
        return False

views.py:

class UserListView(generics.ListCreateAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    permission_classes = [IsDummy]

The issue only happens when I submit a request from my browser on the browsable api. When I submit a GET request at the list url I get the following printed to the terminal from the print statement in the IsDummy permission class:

GET

POST

POST

OPTIONS

When I submit a GET or OPTIONS request through postman I see the single, appropriate, request method that I actually used.

It seems that the first method listed is always the actual method that I used, I have no idea where the extra POSTs and the OPTION are coming from. The even stranger part is that the page will load fine after all of this even though the POST requests should clearly be resulting in IsDummy.has_permission returning a False.

The chrome dev tools show only a single GET request being submitted and since it only seems to happen in the browsable api i'm sure it has something to do with that but I can't figure out what I have messed up to make this happen.

c6754
  • 870
  • 1
  • 9
  • 15
  • browser api is a signle page which can add\update\delete instance,when you ask this page,drf will check all required permission to see if the corresponding module need display – Ykh Oct 10 '18 at 01:50

1 Answers1

5

Browser API is a single page which can add\update\delete instances. When you ask this page, DRF will check all required permission to see if the corresponding module is allowed to display.

Deep in the DRF source code, you can see this in renderers.py:

class BrowsableAPIRenderer(BaseRenderer):
    """
    HTML renderer used to self-document the API.
    """
    media_type = 'text/html'
    format = 'api'
    template = 'rest_framework/api.html'
    filter_template = 'rest_framework/filters/base.html'
    code_style = 'emacs'
    charset = 'utf-8'
    form_renderer_class = HTMLFormRenderer

    ...

    def get_context(self, data, accepted_media_type, renderer_context):
         ....
         context = {
             ....
            'put_form': self.get_rendered_html_form(data, view, 'PUT', request),
            'post_form': self.get_rendered_html_form(data, view, 'POST', request),
            'delete_form': self.get_rendered_html_form(data, view, 'DELETE', request),
            'options_form': self.get_rendered_html_form(data, view, 'OPTIONS', request),
         }
         return context

    def get_rendered_html_form(self, data, view, method, request):
        ....
        if not self.show_form_for_method(view, method, request, instance):
            ....

    def show_form_for_method(self, view, method, request, obj):
        """
        Returns True if a form should be shown for this method.
        """
        if method not in view.allowed_methods:
            return  # Not a valid method

        try:
            view.check_permissions(request)
            if obj is not None:
                view.check_object_permissions(request, obj)
        except exceptions.APIException:
            return False  # Doesn't have permissions
        return True

view.check_permissions(request) in show_form_for_method is why DRF browsable API is running permission checks on multiple request types for every actual request.

Ted Klein Bergman
  • 9,146
  • 4
  • 29
  • 50
Ykh
  • 7,567
  • 1
  • 22
  • 31
  • 1
    Nice finding :) Does DRF has the same behaviour for API requests? – JPG Oct 10 '18 at 03:07
  • 2
    no,api requests only check the permissions asking url required. – Ykh Oct 10 '18 at 03:15
  • Thanks, just what I was looking for. Is it poor practice to check for the method, e.g. `POST`, in a permissions class? It seems odd that this isn't discussed more. – c6754 Oct 10 '18 at 11:39