[Fixed]-Django Rest Framework use DjangoModelPermissions on ListAPIView

22👍

Ouch, that was easier than I thought:

class CustomDjangoModelPermission(permissions.DjangoModelPermissions):

    def __init__(self):
        self.perms_map = copy.deepcopy(self.perms_map)  # from EunChong's answer
        self.perms_map['GET'] = ['%(app_label)s.view_%(model_name)s']

10👍

@Yannic Hamann’s solution has a small bug. It overwrites parent’s perms_map[‘GET’].

As follows, A dictionary overring need deepcopy.

class CustomDjangoModelPermission(permissions.DjangoModelPermissions):

    def __init__(self):
        self.perms_map = copy.deepcopy(self.perms_map) # you need deepcopy when you inherit a dictionary type 
        self.perms_map['GET'] = ['%(app_label)s.view_%(model_name)s']

dictionary overring test

class Parent:
    perms = {'GET':'I am a Parent !'}

class Child(Parent):
    def __init__(self):
        self.perms['GET'] = 'I am a Child !'

dictionary overring result

>>> print(Parent().perms['GET'])
I am a Parent !

>>> print(Child().perms['GET'])
I am a Child !

>>> print(Parent().perms['GET'])
I am a Child ! # Parent's perms is overwritten by Child.
       ^^^^^  

2👍

You have to override the custome DjangoModelPermissions.

class BaseModelPerm(permissions.DjangoModelPermissions):

     def get_custom_perms(self, method, view):
          app_name = view.model._meta.app_label
          return [app_name+"."+perms for perms in view.extra_perms_map.get(method, [])]

    def has_permission(self, request, view):
       perms = self.get_required_permissions(request.method, view.model)
       perms.extend(self.get_custom_perms(request.method, view))
       return (
          request.user and
          (request.user.is_authenticated() or not self.authenticated_users_only) and
        request.user.has_perms(perms)
    )

in the view you can use like below

class ViewName(generic.ListApiView):

      """ Trip listing view """

     model = model_name
     serializer_class = serializer_class
     permission_classes = (permissions.IsAuthenticated,BaseModelPerm)
     queryset = model.objects.all()
     extra_perms_map = {
      'GET': ["can_view_trip"],
     }

add the whatever extra permissions you want to add.

0👍

Following @Yannic Hamann’s solution by design the developer should not call the init method instead it is called by Python when an instance of the class is created,
for scalability, you can add new permission to the dictionary in your custom model permission

class CustomModelPermissions(permissions.DjangoModelPermissions):
    """
    Custom ModelPermissions:
        -This permission must only be applied to views that have a .queryset property or get_queryset() method
        -Authorization will only be granted if the user is authenticated and has the relevant model permissions assigned
    """

    def get_required_permissions(self, method, model_cls):
        "Use append to add more action to GET,POST,PUT,PATCH As in"

        """
        self.perms_map['GET'].append('%(app_label)s.view_%(model_name)s'), THIS IS TO ENSURE YOU DO NOT OVERIDE THE EXISING METHOD permmsions
        """
        self.perms_map["GET"].append("%(app_label)s.view_%(model_name)s")
        return super().get_required_permissions(method, model_cls)
  

Leave a comment