Last modified: Mar 11, 2025 By Alexander Williams
Custom Django Rest Framework Permissions Guide
Django Rest Framework (DRF) provides built-in permissions for securing APIs. However, custom permissions are often needed for specific use cases. This guide will walk you through creating custom permissions in DRF.
Table Of Contents
Why Use Custom Permissions?
DRF's default permissions like IsAuthenticated
or IsAdminUser
are useful. But they may not fit all scenarios. Custom permissions allow you to define precise access rules for your API endpoints.
Creating a Custom Permission Class
To create a custom permission, subclass BasePermission
and override the has_permission
or has_object_permission
methods. Below is an example:
from rest_framework.permissions import BasePermission
class IsOwnerOrReadOnly(BasePermission):
"""
Custom permission to only allow owners of an object to edit it.
"""
def has_object_permission(self, request, view, obj):
# Read permissions are allowed to any request.
if request.method in ['GET', 'HEAD', 'OPTIONS']:
return True
# Write permissions are only allowed to the owner.
return obj.owner == request.user
In this example, the IsOwnerOrReadOnly
class allows read-only access to all users. But only the owner can modify the object.
Using Custom Permissions in Views
Once your custom permission class is ready, apply it to your views. Here's how to use it in a view:
from rest_framework import generics
from .models import MyModel
from .permissions import IsOwnerOrReadOnly
class MyModelDetailView(generics.RetrieveUpdateDestroyAPIView):
queryset = MyModel.objects.all()
serializer_class = MyModelSerializer
permission_classes = [IsOwnerOrReadOnly]
This ensures only the owner can update or delete the object. Other users can only view it.
Testing Custom Permissions
Testing is crucial to ensure your permissions work as expected. Use DRF's APITestCase
to write tests. Here's an example:
from django.urls import reverse
from rest_framework.test import APITestCase
from .models import MyModel
class MyModelPermissionsTest(APITestCase):
def test_owner_can_edit(self):
user = User.objects.create(username='owner')
my_model = MyModel.objects.create(owner=user)
self.client.force_authenticate(user=user)
response = self.client.put(reverse('mymodel-detail', args=[my_model.id]), {'field': 'new_value'})
self.assertEqual(response.status_code, 200)
def test_non_owner_cannot_edit(self):
user = User.objects.create(username='non_owner')
my_model = MyModel.objects.create(owner=User.objects.create(username='owner'))
self.client.force_authenticate(user=user)
response = self.client.put(reverse('mymodel-detail', args=[my_model.id]), {'field': 'new_value'})
self.assertEqual(response.status_code, 403)
These tests verify that only the owner can edit the object. Non-owners receive a 403 Forbidden
response.
Common Use Cases for Custom Permissions
Custom permissions are useful for scenarios like:
- Restricting access to specific user roles.
- Allowing access based on object attributes.
- Implementing complex business logic for access control.
For example, you might restrict access to an API endpoint based on a user's subscription plan. This can be done by checking the user's profile in the has_permission
method.
Best Practices for Custom Permissions
Follow these best practices when writing custom permissions:
- Keep permission logic simple and focused.
- Avoid duplicating logic across multiple permission classes.
- Test permissions thoroughly to ensure they work as expected.
For more advanced use cases, consider combining custom permissions with performance optimization techniques or API security best practices.
Conclusion
Custom permissions in Django Rest Framework are a powerful tool for securing your APIs. By following this guide, you can create and implement custom permissions tailored to your application's needs. Remember to test thoroughly and follow best practices for optimal results.
For further reading, check out our guide on DRF throttling to manage API request rates effectively.