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:
            
            # The method is a safe method
            return True
            
        else:
            # The method isn't a safe method
            # Only owners are granted permissions for unsafe methods
            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)
  
    # Display the owner's username (read-only)
    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.

Customizing Object Level Permissions – Django REST Framework

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. 

Similar Reads

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....

Setting permission policies

...

Making HTTP Requests

...