[Fixed]-Django-rest-framework permissions for create in viewset


Customize the get_queryset method:

def get_queryset(self):
    if self.request.user.is_superuser:
        return User.objects.all()
        return User.objects.filter(id=self.request.user.id)

This way, an authenticated user can only retrieve, modify or delete its own object.

Specify the permission_classes = (AllowAny,) so an authenticated user can create a new one.

EDIT: further explanation from comments

Customizing the get_queryset method this way means the following:

  1. Yes, non-authenticated users can send the GET request to retrieve the user list but it will be empty because the return User.objects.filter(id=self.request.user.id) ensures that only information about the authenticated user is returned.

  2. The same applies for other methods, if an authenticated user tries to DELETE another user object, a detail: Not found will be returned (because the user it is trying to access is not in the queryset).

  3. Authenticated users can do whatever they want to their user objects.



You could utilizing Django REST Framework’s ability to define custom permissions. You can specify both a has_permission and has_object_permission within a custom class. This will give you the expected behavior of throwing 403s to anon users for everything except posting to the creation endpoint. It might look something like:

class IsAnonCreate(permissions.BasePermission):
    def has_permission(self, request, view):
        if request.method == "POST" and not request.user.is_authenticated():
            return True
        elif not request.user.is_authenticated() and request.method != "POST":
            return False
        elif request.method in permissions.SAFE_METHODS:
            return True

        return False

    def has_object_permission(self, request, view, obj):
        if not request.user.is_authenticated():
            return False
        if request.method in permissions.SAFE_METHODS:
            return True

        return obj.username == request.user.username

You could then add some custom handling for authenticated users if you wanted.

Then all you need to do is add the permission class to your ModelViewSet:

class UserViewSet(viewsets.ModelViewSet):

    API endpoint that allows users to be viewed or edited.
    queryset = User.objects.all()
    serializer_class = UserSerializer
    permission_classes = (IsAnonCreate, )


This is based on @argaen answer and it worked for me:

class UserViewSet(viewsets.ModelViewSet):
    serializer_class = UserSerializer
    permission_classes = (AllowAny,)
    authentication_classes = (NoAuthentication,)
    filter_backends = (filters.DjangoFilterBackend,)
    filter_fields = ('id', 'email', 'name')

    def get_queryset(self):
        user = TokenAuthentication().authenticate(self.request)
        if user is not None:
            user = user[0]
            if user.is_superuser:
                return get_user_model().objects.all()
                return get_user_model().objects.filter(id=user.id)

        return get_user_model().objects.none() 

Leave a comment