Skip to main content

Add object permissions to a Django REST Framework endpoint

2026-11-11 16:36:24.316070+00:00
Add object permissions to a Django REST Framework endpoint

Requiring login does not establish that a user owns the requested record. A notes endpoint needs an ownership rule for detail access, list access and creation. Each path reaches authorization through a different part of the view lifecycle.

Authentication and an ownership-scoped queryset constrain which records a request can access.

Scope the queryset and assign ownership

This fragment assumes a toy Note model with an owner ForeignKey and a serializer whose owner field is read-only.

from rest_framework import permissions, viewsets

class IsOwner(permissions.BasePermission):
    def has_object_permission(self, request, view, obj):
        return obj.owner_id == request.user.pk

class NoteViewSet(viewsets.ModelViewSet):
    serializer_class = NoteSerializer
    permission_classes = [permissions.IsAuthenticated, IsOwner]

    def get_queryset(self):
        return Note.objects.filter(owner=self.request.user)

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

Filtering the queryset makes the list return only the current user's notes. Detail retrieval also starts from that filtered set, so another user's ID cannot be used to fetch or mutate a note through the usual generic view path.

The explicit object permission documents the ownership requirement and helps protect future code paths that retrieve an object differently. If a custom action bypasses get_object(), it must still enforce the appropriate checks.

Ownership comes from the authenticated request. A client-supplied owner ID must not decide who owns a new note. The serializer should reject or ignore writable ownership input according to a documented contract.

Exercise more than GET detail

Create two synthetic users with different notes. Check that each list omits the other user's records. Try retrieving, changing and deleting another user's note. Then send a create payload that includes a different owner and confirm the saved record belongs to the authenticated caller.

Authentication failure status can depend on the configured authentication classes. Assert the application's intended contract instead of assuming every unauthorized request must return one universal status.

For team-owned records, owner equality is insufficient. Build the queryset from active workspace membership and check role-specific actions such as editing or deletion. Membership revocation must affect subsequent requests and any cached results.

An object-permission class alone does not filter list results, and it does not decide creation ownership. Keeping those checks explicit makes a future endpoint review much easier.

The Nirogidhara case study offers related operational context. DRF's permissions guide explains object-level limitations, while its serializer guide covers read-only fields.