Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django Rest Framework use DjangoModelPermissions on ListAPIView

I am playing around with the djangorestframework and my goal is to use DjangoModelPermissions on my view which reacts to a GET request. The official documentation says:

The default behavior can also be overridden to support custom model permissions. For example, you might want to include a view model permission for GET requests.

Source

So I modified my model like the following:

class User(AbstractUser):
    display_name = models.CharField(_('Display Name'), blank=True, max_length=255)

    class Meta:
        permissions = (
            ("view_user", "Can view users"),
        )

    def __str__(self):
        return self.username

And the view:

class UserListAPIView(ListAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    permission_classes = (permissions.DjangoModelPermissions,)

Settings:

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework.authentication.TokenAuthentication',
    ),
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.DjangoModelPermissions'
    ]
}

The problem is that my implemented UserListAPIView successfully returns a list of all objects to a user who doesn't belong to a Group neither has any custom User Permission. It seems to me that the DjangoModelPermissions takes no effect.

like image 962
Yannic Hamann Avatar asked Oct 05 '17 11:10

Yannic Hamann


People also ask

What is DjangoModelPermissions?

DjangoModelPermissions allows us to set any combination of permissions to each of the users separately. The permission then checks if the user is authenticated and if they have add , change , or delete user permissions on the model.

How does Django REST Framework authentication work?

Authentication is the mechanism of associating an incoming request with a set of identifying credentials, such as the user the request came from, or the token that it was signed with. The permission and throttling policies can then use those credentials to determine if the request should be permitted.


Video Answer


2 Answers

@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.
       ^^^^^  
like image 143
EunChong Lee Avatar answered Nov 15 '22 20:11

EunChong Lee


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']
like image 26
Yannic Hamann Avatar answered Nov 15 '22 19:11

Yannic Hamann