Customizing Object Level Permissions – Django REST Framework
Last Updated :
14 Sep, 2021
In this article, we will discuss how to customize Object Level Permissions in Django REST Framework. To customize permission classes in Django REST Framework, we should inherit the rest_framework.permissions.BasePermission class and implement either or both of the following methods:
- .has_permission(self, request, view)
- .has_object_permission(self, request, view, obj)
If we look at our robot model mentioned in Browsable API in Django REST Framework, we can notice that any authenticated user can delete the robots even after setting the permission policies in our RESTFul web service. Here comes the importance of customizing the object-level permission so that only a robot owner can update or delete an existing robot.
Creating customized permission class
Go to the robots folder that has the views.py file and create a new file named custompermission.py. You can write the below code in the new file.
Python3
from rest_framework import permissions
class IsCurrentUserOwnerOrReadOnly(permissions.BasePermission):
def has_object_permission( self , request, view, obj):
if request.method in permissions.SAFE_METHODS:
return True
else :
return obj.owner = = request.user
|
The IsCurrentUserOwnerOrReadOnly inherits from the BasePermission class and overrides the has_object_permission method. The method returns a bool value, which indicates whether the permission should be granted or not. The has_object_permission differentiates the safe and unsafe methods, and only owners are granted permission for unsafe methods.
Let’s add the owner field to the robots/models.py file.
owner = models.ForeignKey(
'auth.User',
related_name= 'robots',
on_delete=models.CASCADE
)
The Robot class looks as follows:
Python3
class Robot(models.Model):
CURRENCY_CHOICES = (
( 'INR' , 'Indian Rupee' ),
( 'USD' , 'US Dollar' ),
( 'EUR' , 'Euro' ),
)
name = models.CharField(max_length = 150 , unique = True )
robot_category = models.ForeignKey(
RobotCategory,
related_name = 'robots' ,
on_delete = models.CASCADE)
manufacturer = models.ForeignKey(
Manufacturer,
related_name = 'robots' ,
on_delete = models.CASCADE)
currency = models.CharField(
max_length = 3 ,
choices = CURRENCY_CHOICES,
default = 'INR' )
price = models.IntegerField()
manufacturing_date = models.DateTimeField()
owner = models.ForeignKey(
'auth.User' ,
related_name = 'robots' ,
on_delete = models.CASCADE
)
class Meta:
ordering = ( 'name' ,)
def __str__( self ):
return self .name
|
In the above code, we specified the models.CASCADE value so that whenever we delete a user, the robots associated with this user will be deleted too.
Now let’s add the owner field to the RobotSerializer class mentioned in the robots/serializers.py file. You can add the below code
owner = serializers.ReadOnlyField(source='owner.username')
The RobotSerializer class looks as follows:
Python3
class RobotSerializer(serializers.HyperlinkedModelSerializer):
robot_category = serializers.SlugRelatedField(
queryset = RobotCategory.objects. all (), slug_field = 'name' )
manufacturer = serializers.SlugRelatedField(
queryset = Manufacturer.objects. all (), slug_field = 'name' )
currency = serializers.ChoiceField(
choices = Robot.CURRENCY_CHOICES)
currency_name = serializers.CharField(
source = 'get_currency_display' ,
read_only = True )
owner = serializers.ReadOnlyField(source = 'owner.username' )
class Meta:
model = Robot
fields = '__all__'
|
Let’s create two new serializer classes named UserRobotSerializer class and UserSerializer class. You can add the below-mentioned code:
Python3
class UserRobotSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Robot
fields = (
'url' ,
'name' )
class UserSerializer(serializers.HyperlinkedModelSerializer):
robots = UserRobotSerializer(
many = True ,
read_only = True )
class Meta:
model = User
fields = (
'url' ,
'pk' ,
'username' ,
'robots' )
|
The UserRobotSerializer class serializes the drones related to a user. Here we haven’t used RobotSerializer because we only need to serialize fewer fields. The UserSerializer class declares a ‘robots’ attribute as an instance of UserRobotSerializer class.
Next, we need to save information about users that make requests. To achieve this we need to override the perform_create method in the RobotList class declared in the views.py file. The new RobotList class looks as follows
Python3
class RobotList(generics.ListCreateAPIView):
queryset = Robot.objects. all ()
serializer_class = RobotSerializer
name = 'robot-list'
def perform_create( self , serializer):
serializer.save(owner = self .request.user)
|
The perform_create method passes the owner information to the create method using the serializer.save method.
Here, we have added a new owner field to the robot table. You can execute the migrations to reflect the changes to the database. Remember, we need to assign a default owner to our existing robots in the table. Let’s note the id of an existing user and provide it during the migration process. You can get the id using the Django shell. Sharing the screenshot for reference:

Now let’s do the migration process. Here, the Django will display the following message:

Now run the “python manage.py migrate” command to apply the generated migrations.
Setting permission policies
You can mention the BasicAuthentication class in the settings.py file.
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES':(
'rest_framework.authentication.BasicAuthentication',
)
}
Now, let’s configure permission policies for RobotList and RobotDetail class-based views. You should import the permissions and custom permission.
from rest_framework import permissions
from robots import custompermission
The new code is as follows:
Python3
class RobotList(generics.ListCreateAPIView):
permission_classes = (
permissions.IsAuthenticatedOrReadOnly,
custompermission.IsCurrentUserOwnerOrReadOnly,
)
queryset = Robot.objects. all ()
serializer_class = RobotSerializer
name = 'robot-list'
def perform_create( self , serializer):
serializer.save(owner = self .request.user)
class RobotDetail(generics.RetrieveUpdateDestroyAPIView):
permission_classes = (
permissions.IsAuthenticatedOrReadOnly,
custompermission.IsCurrentUserOwnerOrReadOnly,
)
queryset = Robot.objects. all ()
serializer_class = RobotSerializer
name = 'robot-detail'
|
Making HTTP Requests
Let’s try to get the robot details. Since it’s a safe method, our custom permission will provide the robot details without any user credentials. The HTTPie command is as follows:
http :8000/robot/
The output is as follows:
HTTP/1.1 200 OK
Allow: GET, POST, HEAD, OPTIONS
Content-Language: en
Content-Length: 2116
Content-Type: application/json
Date: Sun, 29 Aug 2021 07:11:39 GMT
Referrer-Policy: same-origin
Server: WSGIServer/0.2 CPython/3.7.5
Vary: Accept, Accept-Language
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
[
{
"currency": "USD",
"currency_name": "US Dollar",
"manufacturer": "Fanuc",
"manufacturing_date": "2019-10-12T00:00:00Z",
"name": "FANUC M-710ic/50",
"owner": "sonu",
"price": 37000,
"robot_category": "Articulated Robots",
"url": "http://localhost:8000/robot/1/"
},
{
"currency": "USD",
"currency_name": "US Dollar",
"manufacturer": "ABB",
"manufacturing_date": "2020-05-10T00:00:00Z",
"name": "IRB 1100",
"owner": "sonu",
"price": 25000,
"robot_category": "Articulated Robots",
"url": "http://localhost:8000/robot/7/"
},
]
Now let’s try to delete a robot. According to the custom permission class, only the robot owner can perform the delete operation. Let’s try to delete the robot by providing the superuser credential. The HTTPie command is as follows:
http -a “admin”:”admin@123″ DELETE :8000/robot/1/
Output:

Let’s try the delete operation by providing the owner credentials. The command is as follows:
http -a “sonu”:”sn@pswrd” DELETE :8000/robot/1/
Output:

You can notice that the robot has been removed successfully from the database.
Similar Reads
Adding Permission in API - Django REST Framework
There are many different scenarios to consider when it comes to access control. Allowing unauthorized access to risky operations or restricted areas results in a massive vulnerability. This highlights the importance of adding permissions in APIs. Â Django REST framework allows us to leverage permiss
7 min read
Customizing Filters in Django REST Framework
Prerequisite: Adding Filtering in APIs â Django REST Framework [link needed article on published yet] Django filters facilitate filtering the queryset to retrieve the relevant results based on the values assigned to the filter fields. But, what if the user wants to retrieve details within a given ra
4 min read
How to return custom JSON in Django REST Framework ?
In this article, we will create class-based views and combine this with the serializer class to return JSON representation for each HTTP request. For our class-based views, we will make use of a set of generic views, which help to achieve minimum lines code. Generic Classes and ViewsetsHTTP requests
9 min read
Concrete GenericAPIViews in Django Rest Framework.
Django Rest Framework (DRF) provides powerful tools for building RESTful APIs in Django projects. One of the key components of DRF is Concrete GenericAPIViews, which offer pre-implemented views for common CRUD (Create, Read, Update, Delete) operations. In this article, we will see Concrete GenericAP
2 min read
Django REST Framework Installation
Django REST Framework can be installed via pip package similar to Django installation. Since Django REST Framework is a wrapper over default Django Framework, to install it, Django should be installed already. Now to install rest framework follow the below process. Prerequisites Python Pip Django Ho
1 min read
Creating and Using Serializers - Django REST Framework
In Django REST Framework the very concept of Serializing is to convert DB data to a datatype that can be used by javascript. Serializers allow complex data such as querysets and model instances to be converted to native Python datatypes that can then be easily rendered into JSON, XML or other conten
3 min read
DictField in serializers - Django REST Framework
In Django REST Framework the very concept of Serializing is to convert DB data to a datatype that can be used by javascript. Every serializer comes with some fields (entries) which are going to be processed. For example if you have a class with name Employee and its fields as Employee_id, Employee_n
4 min read
Implement Token Authentication using Django REST Framework
Token authentication refers to exchanging username and password for a token that will be used in all subsequent requests so to identify the user on the server side.This article revolves about implementing token authentication using Django REST Framework to make an API. The token authentication works
2 min read
Python | User groups with Custom permissions in Django
Let's consider a trip booking service, how they work with different plans and packages. There is a list of product which subscriber gets on subscribing to different packages, provided by the company. Generally, the idea they follow is the level-wise distribution of different products. Let's see the
4 min read
JWT Authentication with Django REST Framework
JSON Web Token is an open standard for securely transferring data within parties using a JSON object. JWT is used for stateless authentication mechanisms for users and providers, this means maintaining session is on the client-side instead of storing sessions on the server. Here, we will implement t
2 min read