Reputation: 3
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
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