How do I set up permissions in django-rest-framework so that the session user can only list objects which have a foreign key to that user?

StackOverflow https://stackoverflow.com/questions/23447157

Вопрос

I have models like this:

class TheModel(models.Model):
    name = models.CharField(max_length=10)
    owner = models.ForeignKey(settings.AUTH_USER_MODEL)

I'd like to create an API view which lists all of TheModel objects wherein TheModel.owner equals request.user.

I think I can do this by overriding get_queryset, but it seems like I should be using a custom BasePermission. The problem is that it doesn't look like BasePermission.has_object_permission is run on each object in a list view. The only thing that gets run is BasePermission.has_permission. I tested this with this :-

class TheModelViewSet(viewsets.ModelViewSet):
    model = TheModel
    permission_classes = [IsOwner]

class IsOwner(permissions.BasePermission):
    def has_permission(self, request, view):
        print("checking has permission for {}".format(request.user))
        return True

    def has_object_permission(self, request, view, obj):
        print("checking permission for {} on {}").format(request.user, obj.user)

        return obj.owner == request.user

The only thing that gets printed is the stuff from IsOwner.has_permission.

Maybe I'm just over thinking it and I should just be using custom querysets instead of using permissions?

Это было полезно?

Решение

The official documentation recommends using a custom get_queryset method in this use-case, and that's exactly what I would do.

The permission object's has_object_permission only runs when called on a view for a single object, so that won't work to enforce permissions for list views.

Basically, you are not trying to allow or deny access, you are trying to filter the results. Filtering on a database level is the fastest, easiest and most secure (least error-prone) option. The permission framework is only made to either allow or deny access to an object or a complete object group, it is not made to filter the content of a particular response. The get_queryset method is made to filter the content of a particular response, and should be used as such.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top