Django rest framework - Limiting get request access to only authorized user

You can see in this serializer I am checking that the authenticated user matches the instance's user:

class CreateSupplierSerializer(serializers.ModelSerializer):
    name = serializers.CharField(max_length=200)
    email = serializers.EmailField(max_length=200)
    phone = serializers.IntegerField()

    def update(self, instance, validated_data):
        if str(self.context['request'].user) != str(instance.username):
            raise exceptions.PermissionDenied('You do not have permission to update')
            
        supplier = Supplier.objects.create(user=instance, **validated_data)

        return supplier
    class Meta:
        model=Supplier
        fields=['name','email','phone']

I am wondering how I can implement this same method into my get request, here is my get request format...

models.py:

class UserProfile(models.Model):
    user = models.OneToOneField(User,on_delete=models.CASCADE)
    bio = models.CharField(max_length=200)
    email = models.CharField(max_length=200)

class Supplier(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    name = models.CharField(max_length=200)
    phone = models.IntegerField()
    email = models.EmailField(max_length=200)

views.py:

class getsuppliers(viewsets.ModelViewSet):
    queryset = User.objects.all()
    serializer_class = GetSuppliersSerializer
    lookup_field = 'username'

serializers.py:

class SuppliersSerializer(serializers.ModelSerializer):
    class Meta:
        model = Supplier
        fields = ['pk','user','name','email','phone']

class GetSuppliersSerializer(serializers.ModelSerializer):
    supplier_set = SuppliersSerializer(read_only=True, many=True)
    class Meta:
        model = User
        fields = ['supplier_set']

You can override the retrieve method of viewsets.ModelViewSet to achieve a similar kind of behavior. Later call the default retrieve.

class getsuppliers(viewsets.ModelViewSet):
    queryset = Supplier.objects.all()
    serializer_class = GetSuppliersSerializer
    lookup_field = 'username'

    def retrieve(self, request, *args, **kwargs):
        if self.request.user != self.get_object().username:
            raise exceptions.PermissionDenied('You do not have permission to update')
        super().retrieve(request, *args, **kwargs)

Many thanks to @Uzzal H. Mohammad for pointing me to the retrieve function... here is a working solution

class getsuppliers(viewsets.ModelViewSet):
    queryset = User.objects.all()
    serializer_class = GetSuppliersSerializer
    lookup_field = 'username'

    def retrieve(self, request, *args, **kwargs):
        if str(self.request.user) != self.get_object().username:
            raise exceptions.PermissionDenied('You do not have permission to update')
        instance = self.get_object()
        return Response(self.serializer_class(instance).data)

I think the better, reusable, solution is to use the Permissions, which are made for these use cases.

Create a permission to describe what you want to do

class IsOwner(BasePermission):

    def has_object_permission(self, request, view, obj):
        return request.user == obj.user

Then add permission_classes = [IsOwner] to your view.

Back to Top