DRF: custom permission for company-scoped orders and manager-only cancel

Backend Live Coding November 13, 2026 python

has_object_permission is called only by get_object(), not on list endpoints.

python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# ======================================================================
# Q: Write a custom permission: a user sees only the orders of their own
# company, and only a manager can cancel.
#
# has_object_permission is called only by get_object(), not on list endpoints.
# That is why filtering in get_queryset() is mandatory.
# ======================================================================

class IsCompanyManager(BasePermission):
    def has_permission(self, request, view):
        return request.user.is_authenticated

    def has_object_permission(self, request, view, obj):
        if obj.customer.company_id != request.user.company_id:
            return False
        if view.action == 'cancel':
            return request.user.role == 'manager'
        return True

class OrderViewSet(viewsets.ReadOnlyModelViewSet):
    permission_classes = [IsCompanyManager]
    serializer_class = OrderSerializer

    def get_queryset(self):     # the first and most important filter
        return (Order.objects.filter(customer__company_id=self.request.user.company_id)
                .select_related('customer').prefetch_related('items__product'))

    @action(detail=True, methods=['post'])
    def cancel(self, request, pk=None):
        order = self.get_object()          # calls has_object_permission
        services.cancel_order(order, by=request.user)
        return Response(status=status.HTTP_204_NO_CONTENT)