Custom Permissions0%

Custom Permissions

Beginner12 min read•Updated: Jul 11, 2026
Study MaterialsCheatsheet

DRF Custom Permission Classes and Object-Level Permissions

Authentication identifies who a user is; permissions determine what that user is authorized to perform. While built-in classes (IsAuthenticated, AllowAny, IsAdminUser) handle basic access control, enterprise applications require fine-grained Custom Permission Classes and Object-Level Permissions (e.g. only the document author or organization admin can delete a file).


1. Built-in DRF Permission Classes

  • AllowAny: Unrestricted public access (e.g. user signup, public landing pages).
  • IsAuthenticated: Denies access to anonymous users.
  • IsAdminUser: Grants access strictly to staff users (user.is_staff == True).
  • IsAuthenticatedOrReadOnly: Authenticated users can mutate data; anonymous users are granted read-only access (GET, HEAD, OPTIONS).

2. Anatomy of a Custom Permission Class

A permission class inherits from rest_framework.permissions.BasePermission and implements one or both of these methods:

  1. 1
    has_permission(self, request, view): Evaluates view-level access (e.g. whether the user can access the /articles/ endpoint at all).
  2. 2
    has_object_permission(self, request, view, obj): Evaluates object-level access on a specific instance (e.g. whether the user can mutate Article #42).

3. Implementing IsOwnerOrReadOnly Object Permission

A classic enterprise permission: any user can read a document, but only the original author can edit or delete it:

Python
# api/permissions.py
from rest_framework import permissions
 
class IsOwnerOrReadOnly(permissions.BasePermission):
'''
Object-level permission to only allow authors of an object to edit or delete it.
Assumes model instance has an `author` attribute.
'''
 
def has_permission(self, request, view):
# View-level check: Allow all authenticated users
return request.user and request.user.is_authenticated
 
def has_object_permission(self, request, view, obj):
# 1. Read permissions are allowed for any request (GET, HEAD, OPTIONS)
if request.method in permissions.SAFE_METHODS:
return True
 
# 2. Write permissions are strictly restricted to the author or superuser
return obj.author == request.user or request.user.is_staff

4. Role-Based Organization Permission Class

Python
# api/permissions.py
from rest_framework.permissions import BasePermission
 
class IsOrganizationAdmin(BasePermission):
message = "You must be an Organization Administrator to perform this action."
 
def has_permission(self, request, view):
return (
request.user.is_authenticated
and getattr(request.user, "role", None) == "admin"
)

5. Applying Permissions to ViewSets

Python
# articles/views.py
from rest_framework.viewsets import ModelViewSet
from .models import Article
from .serializers import ArticleSerializer
from .permissions import IsOwnerOrReadOnly
 
class ArticleViewSet(ModelViewSet):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
# Attach custom permission class
permission_classes = [IsOwnerOrReadOnly]
lookup_field = "slug"
 
def perform_create(self, serializer):
serializer.save(author=self.request.user)

Interactive Quiz

Practice Quiz

Question 1
What is the difference between has_permission and has_object_permission in DRF?
Question 2
What HTTP methods are defined in permissions.SAFE_METHODS?
Question 3
When does DRF execute has_object_permission checks?
Question 4
How do you customize the error message returned when a custom permission class denies access?
Question 5
If a view defines permission_classes = [IsAuthenticated, IsAdminUser], what must be true for a request to succeed?
Next Lesson

Filtering API results

Continue learning with hands-on practice, examples, and exercises in the upcoming topic.

Related Lessons

Previous LessonNext Lesson
JWT AuthenticationFiltering API results

Practice Quiz

Test your understanding of this lesson with 5 questions. Each question has one correct answer.

PrevNext