En este artículo, discutiremos cómo personalizar los permisos de nivel de objeto en Django REST Framework. Para personalizar las clases de permisos en Django REST Framework, debemos heredar la clase rest_framework.permissions.BasePermission e implementar uno o ambos de los siguientes métodos:
- .has_permission(auto, solicitud, vista)
- .has_object_permission(self, request, view, obj)
Si observamos nuestro modelo de robot mencionado en la API navegable en Django REST Framework , podemos notar que cualquier usuario autenticado puede eliminar los robots incluso después de configurar las políticas de permisos en nuestro servicio web RESTFul. Aquí viene la importancia de personalizar el permiso a nivel de objeto para que solo el propietario de un robot pueda actualizar o eliminar un robot existente.
Creación de una clase de permiso personalizada
Vaya a la carpeta de robots que tiene el archivo views.py y cree un nuevo archivo llamado custompermission.py . Puede escribir el siguiente código en el nuevo archivo.
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
IsCurrentUserOwnerOrReadOnly hereda de la clase BasePermission y anula el método has_object_permission . El método devuelve un valor booleano, que indica si se debe otorgar el permiso o no. has_object_permission diferencia los métodos seguros e inseguros, y solo los propietarios tienen permiso para los métodos inseguros.
Agreguemos el campo de propietario al archivo robots/models.py.
owner = models.ForeignKey( 'auth.User', related_name= 'robots', on_delete=models.CASCADE )
La clase Robot tiene el siguiente aspecto:
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
En el código anterior, especificamos el valor models.CASCADE para que cada vez que eliminemos un usuario, los robots asociados con este usuario también se eliminarán.
Ahora agreguemos el campo de propietario a la clase RobotSerializer mencionada en el archivo robots/serializers.py. Puede agregar el siguiente código
owner = serializers.ReadOnlyField(source='owner.username')
La clase RobotSerializer tiene el siguiente aspecto:
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__'
Vamos a crear dos nuevas clases de serializador llamadas clase UserRobotSerializer y clase UserSerializer. Puede agregar el código mencionado a continuación:
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')
La clase UserRobotSerializer serializa los drones relacionados con un usuario. Aquí no hemos usado RobotSerializer porque solo necesitamos serializar menos campos. La clase UserSerializer declara un atributo ‘robots’ como una instancia de la clase UserRobotSerializer.
A continuación, debemos guardar información sobre los usuarios que realizan requests. Para lograr esto, debemos anular el método perform_create en la clase RobotList declarada en el archivo views.py . La nueva clase RobotList tiene el siguiente aspecto
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)
El método perform_create pasa la información del propietario al método create utilizando el método serializer.save.
Aquí, hemos agregado un nuevo campo de propietario a la tabla de robots. Puede ejecutar las migraciones para reflejar los cambios en la base de datos. Recuerde, debemos asignar un propietario predeterminado a nuestros robots existentes en la tabla. Anotemos la identificación de un usuario existente y proporcionémosla durante el proceso de migración. Puede obtener la identificación usando el shell de Django. Compartiendo la captura de pantalla como referencia:
Ahora hagamos el proceso de migración. Aquí, Django mostrará el siguiente mensaje:
Ahora ejecute el comando » python manage.py migrate » para aplicar las migraciones generadas.
Configuración de políticas de permisos
Puede mencionar la clase BasicAuthentication en el archivo settings.py.
REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES':( 'rest_framework.authentication.BasicAuthentication', ) }
Ahora, configuremos las políticas de permisos para las vistas basadas en clases de RobotList y RobotDetail. Debe importar los permisos y el permiso personalizado.
from rest_framework import permissions from robots import custompermission
El nuevo código es el siguiente:
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'
Realización de requests HTTP
Intentemos obtener los detalles del robot. Dado que es un método seguro, nuestro permiso personalizado proporcionará los detalles del robot sin ninguna credencial de usuario. El comando HTTPie es el siguiente:
http:8000/robot/
La salida es la siguiente:
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/" }, ]
Ahora intentemos eliminar un robot. De acuerdo con la clase de permiso personalizada, solo el propietario del robot puede realizar la operación de eliminación. Intentemos eliminar el robot proporcionando la credencial de superusuario. El comando HTTPie es el siguiente:
http -a “admin”:”admin@123″ ELIMINAR :8000/robot/1/
Producción:
Probemos la operación de eliminación proporcionando las credenciales del propietario. El comando es el siguiente:
http -a “sonu”:”sn@pswrd” ELIMINAR :8000/robot/1/
Producción:
Puede notar que el robot se ha eliminado con éxito de la base de datos.
Publicación traducida automáticamente
Artículo escrito por SonuGeorge y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA