-->

DjangoRestFramework - How to properly seperate has

2019-09-02 14:49发布

问题:

Here is my permission class:

class IsCreationOrFollowOrOwnerOrReadOnly(permissions.BasePermission):
    """
    Allow any users to create, get and follow objects. Allow only owners to
    PUT, PATCH and DELETE.
    """
    def has_permission(self, request, view):
        if request.method in permissions.SAFE_METHODS or request.user.is_staff:
            return True

        if view.action == 'create':
            return True

        return False

    def has_object_permission(self, request, view):
        if request.method in permissions.SAFE_METHODS or request.user.is_staff or view.action=='follow':
            return True

        try:
            return obj.owner == request.user
        except:
            return obj == request.user # If obj Is request.user

To follow an object, you have to use the follow action. This is my viewset:

class {ageViewSet(viewsets.ModelViewSet):
    queryset = Page.objects.all()
    serializer_class = PageSerializer
    permission_classes = (IsAuthenticated, IsCreationOrFollowOrOwnerOrReadOnly,)

    def perform_create(self, serializer):
        serializer.save(owner=self.request.user, location=self.request.user.userextended.location)

    @detail_route(methods=['post'])
    def follow(self, request, pk=None):
        page = self.get_object()    

        page.users.add(request.user)

        return Response(status=status.HTTP_204_NO_CONTENT)

The issue is, when I try to follow an object, it gives me a 403_FORBIDDEN status code. I'm assuming this is because in has_permission, I have to add this line:

if view.action=='follow':
    return True

But even if I add that line, I get a 403_FORBIDDEN error when an owner tries to PUT to his own object (this is probably because in my has_permission method I don't have if view.action == 'update': return True but PUT, PATCH and DELETE all depend on the object itself (if obj.owner == request.user) so how do I properly allow only users to PUT, PATCH and DELETE while allowing any users to FOLLOW objects (FOLLOW is also an object level permission so placing that in has_permission doesn't make sense to me since it has to do with objects).

回答1:

You don't need to override has_permission. Just override the has_object_permission and do like:

def has_object_permission(self, request, view, obj):
    if request.method in permissions.SAFE_METHODS or request.user.is_staff or obj.owner == request.user:
        return True

    if request.method=='POST':
        return True

    return False

This way owner and staff can perform any action. But a user can only get, post and follow.