0

I am sure that this is fairly straightforward, but I have scoured the documentation and I can't quite figure out how to do this.

I have extended my User class to have two ManyToMany relationships to other users: trainers and teammates.

If a user owns an object (defined by a user ForeignKey on the model), then that user should be able to GET, POST, PUT, PATCH, and DELETE. I have set up these endpoints with ModelViewSet. If a user is a trainer of the owner, they should have the same privileges. If a user is a teammate of the owner, they should only be able to GET.

In a list view of these objects, a user should only see the objects they own and the objects where they are a trainer or teammate of the owner. If they try and access a detail view of an object where they are not the friend or the teammate of the owner, it should return a 403.

I extended BasePermission as follows to try and create this behavior -- I then added it to the ModelViewSet where I wanted this behavior.

class TrainerAndOwnerOrTeammate(permissions.BasePermission):

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

        if user == owner:
            return True

        if user in owner.trainers.all():
            return True

        if user in owner.teammates.all():
            return request.method in permissions.SAFE_METHODS

        return False

Since the REST Framework documentation specifies that this isn't run on a per-object basis for list views, I overrode get_queryset to filter by the request user.

The issue is now I get a 404 error, not a 403, if I try and access a detail view I shouldn't have access to. I understand why that's happening, but is there a way to fix it?

Zach Zundel
  • 395
  • 3
  • 15

2 Answers2

0

I think one solution is to drop get_queryset() and define a custom filter. Filter classes let you filter the queryset based on the request and view being accessed. Another way is to split your viewset into multiple individual views. Another way is to define get_object.

Mad Wombat
  • 14,490
  • 14
  • 73
  • 109
0

I ended up overriding the list method of the ModelViewSet and keeping the permission class. The permission class handled the detail views and actions, and the list method handled the list view.

Zach Zundel
  • 395
  • 3
  • 15