Including security and permissions-related data to models

We want each drone to have an owner. Only an authenticated user will be able to create a drone and it will automatically become the owner of this new drone. We want only the owner of a drone to be able to update or delete the drone. Hence, an authenticated user that is also the owner of the drone will be able to execute PATCH, PUT, and DELETE methods on the drone resource that he owns.

Any authenticated user that isn't the owner of a specific drone resource will have read-only access to this drone. In addition, unauthenticated requests will also have read-only access to drones.

We will combine authentication with specific permissions. Permissions use the authentication information included in the request.user and request.auth attributes to determine whether the request should be granted or denied access. Permissions allow us to control which types of users will be granted or denied access to the different features, methods, resources, or resource collections of our RESTful Web Service.

We will use the permissions features in the Django REST framework to allow only authenticated users to create new drones and automatically become their owners. We will make the necessary changes in the models to make a drone have a user as its owner. We will take advantage of the out-of-the-box permission classes included in the framework combined with a customized permission class, to define the previously explained permission policies for the drones and their related HTTP verbs supported in our web service.

In this case, we will stay focused on security and permissions and we will leave throttling rules for the next chapters. Bear in mind that throttling rules also determine whether a specific request must be authorized or not. However, we will work on throttling rules later and we will combine them with authentication and permissions.

Open the restful01/drones/models.py file and replace the code that declares the Drone class with the following code. The new lines are highlighted in the code listing. The code file for the sample is included in the hillar_django_restful_08_01 folder, in the restful01/drones/models.py file:

class Drone(models.Model): 
    name = models.CharField(max_length=250, unique=True) 
    drone_category = models.ForeignKey( 
        DroneCategory,  
        related_name='drones',  
        on_delete=models.CASCADE) 
    manufacturing_date = models.DateTimeField() 
    has_it_competed = models.BooleanField(default=False) 
    inserted_timestamp = models.DateTimeField(auto_now_add=True) 
    owner = models.ForeignKey( 
        'auth.User',  
        related_name='drones', 
        on_delete=models.CASCADE) 
 
    class Meta: 
        ordering = ('name',) 
 
    def __str__(self): 
        return self.name

The highlighted lines declare a new owner field for the Drone model. The new field uses the django.db.models.ForeignKey class to provide a many-to-one relationship to the django.contrib.auth.User model.

This User model persists the users for the Django authentication system. Now, we are using this authentication system for our RESTful Web Service. The 'drones' value specified for the related_name argument creates a backward relation from the User to the Drone model. Remember that this value indicates the name to use for the relation from the related User object back to a Drone object. This way, we will be able to access all the drones owned by a specific user.

Whenever we delete a User, we want all drones owned by this user to be deleted too, and therefore, we specified the models.CASCADE value for the on_delete argument.

Open the restful01/drones/serializers.py file and add the following code after the last line that declares the imports, before the declaration of the DroneCategorySerializer class. The code file for the sample is included in the hillar_django_restful_08_01 folder, in the restful01/drones/serializers.py file:

from django.contrib.auth.models import User 
 
 
class UserDroneSerializer(serializers.HyperlinkedModelSerializer): 
    class Meta: 
        model = Drone 
        fields = ( 
            'url', 
            'name') 
 
 
class UserSerializer(serializers.HyperlinkedModelSerializer): 
    drones = UserDroneSerializer( 
        many=True,  
        read_only=True) 
 
    class Meta: 
        model = User 
        fields = ( 
            'url',  
            'pk', 
            'username', 
            'drone')

We don't want to use the DroneSerializer serializer class for the drones related to a user because we want to serialize fewer fields, and therefore, we created the UserDroneSerializer class. This class is a subclass of the HyperlinkedModelSerializer class. This new serializer allows us to serialize the drones related to a User. The UserDroneSerializer class defines a Meta inner class that declares the following two attributes:

  • model: This attribute specifies the model related to the serializer, that is, the Drone class.
  • fields: This attribute specifies a tuple of string whose values indicate the field names that we want to include in the serialization from the related model. We just want to include the URL and the drone's name, and therefore, the code includes 'url' and 'name' as members of the tuple.

The UserSerializer is a subclass of the HyperlinkedModelSerializer class. This new serializer class declares a drones attribute as an instance of the previously explained UserDroneSerializer class, with the many and read_only arguments equal to True because it is a one-to-many relationship and it is read-only. The code specifies the drones name that we specified as the string value for the related_name argument when we added the owner field as a models.ForeignKey instance in the Drone model. This way, the drones field will provide us with an array of URLs and names for each drone that belongs to the user.

Now, we will add an owner field to the existing DroneSerializer class. Open the restful01/drones/serializers.py file and replace the code that declares the DroneSerializer class with the following code. The new lines are highlighted in the code listing. The code file for the sample is included in the hillar_django_restful_08_01 folder, in the restful01/drones/serializers.py file.

class DroneSerializer(serializers.HyperlinkedModelSerializer): 
    # Display the category name 
    drone_category = serializers.SlugRelatedField(queryset=DroneCategory.objects.all(), slug_field='name') 
    # Display the owner's username (read-only) 
    owner = serializers.ReadOnlyField(source='owner.username')
 
    class Meta: 
        model = Drone 
        fields = ( 
            'url', 
            'name', 
            'drone_category', 
            'owner',
            'manufacturing_date', 
            'has_it_competed', 
            'inserted_timestamp',) 

The new version of the DroneSerializer class declares an owner attribute as an instance of serializers.ReadOnlyField with the source argument equal to 'owner.username'. This way, the serializer will serialize the value for the username field of the related django.contrib.auth.User instance stored in the owner field.

The code uses the ReadOnlyField class because the owner is automatically populated when an authenticated user creates a new drone. It will be impossible to change the owner after a drone has been created with an HTTP POST method call. This way, the owner field will render the username that created the related drone. In addition, we added 'owner' to the fields string tuple within the Meta inner class.

We made the necessary changes to the Drone model and its serializer (the DroneSerializer class) to make drones have owners.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.141.31.125