Denis Nefedov
Denis Nefedov

Reputation: 3

The difference between applying permissions to separate object and list of objects in django rest framework

In my code permissions result differently to object and list of objects.

Let's say we have one model of User:

class User(auth.AbstractBaseUser, auth.PermissionsMixin):
    name = models.CharField(max_length=255, blank=True, null=True)
    profile_status = models.CharField(max_length=255, blank=True, null=True)

and two rows in db:

1. name = "Dennis", profile_status = "private" # (not "public")
2. name = "Robert", profile_status = "private" # (not "public")

and the viewset:

class UsersViewSet(viewsets.CreateListRetrieveUpdateViewSet):
    queryset = models.User.objects.all()            # doesn't matter...
    serializer_class = serializers.UserSerializer   # doesn't matter...
    filter_class = filters.UsersFilterSet           # doesn't matter...
    permission_classes = [IsProfileAccessStatus('public'),
                          IsReadOnly]

IsProfileAccessStatus('public') django permission returns True if object's profile_status equals 'public':

def IsProfileAccessStatus(access_status=''):

    class IsProfileStatusOf(BasePermission):
        def has_object_permission(self, request, view, obj):
            return hasattr(obj, 'profile_status') and \
                   obj.profile_status== access_status

    return IsProfileStatusOf

Back end returns users at /api/users/ and speicific one at /api/users/:name/.

Different output

On /api/users/Dennis/ drf returns exception according the IsProfileAccessStatus('public') permission. So it's okay.

But for /api/users/ it returns both objects:

[
  { "name": "Dennis", "profile_status": "private" },
  { "name": "Robert", "profile_status": "private" }
]

So the question is Why django permissions are used this way? Why drf permissions are not applied for every instance?

Thank you!

Upvotes: 0

Views: 268

Answers (1)

erik-sn
erik-sn

Reputation: 2600

It is expensive computationally to do this for every user. Imagine if you had hundreds of thousands of them. In the docs:

Limitations of object level permissions

For performance reasons the generic views will not automatically apply object level permissions to each instance in a queryset when returning a list of objects.

Often when you're using object level permissions you'll also want to filter the queryset appropriately, to ensure that users only have visibility onto instances that they are permitted to view.

A work around is probably just to override the list view and use .filter(profile_status__exact='public'

Upvotes: 1

Related Questions