python - template - ifequal django
Django resto-marco por acción permiso (5)
Django tiene una clase de persmissions llamada DjangoObjectPermissions que utiliza Django Guardian como backend de autenticación.
Cuando tienes a Django guardian activo en tu configuración, simplemente agregas permission_classes = [DjandoObjectPermissions]
a tu vista y realiza la autenticación de permisos automáticamente, por lo que puedes ''CRUD'' basado en el conjunto de permisos para un grupo o usuario django.contrib.auth
particular.
Ver una gist con un ejemplo.
Puede configurar Django Guardian como su autenticación respaldada http://django-guardian.readthedocs.org/en/latest/installation.html
Soy un novato en desarrollo con Django + Django Rest-framework y estoy trabajando en un proyecto que proporciona acceso a la API REST. Me preguntaba cuál es la mejor práctica para asignar un permiso diferente a cada acción de un ApiView o Viewset determinado.
Supongamos que definí algunas clases de permisos como ''IsAdmin'', ''IsRole1'', ''IsRole2'', ..., y quiero conceder permisos diferentes a las acciones individuales (por ejemplo, un usuario con Role1 puede crear o recuperar, un usuario con Role2 puede actualizarse, y solo un administrador puede eliminar).
¿Cómo puedo estructurar una vista basada en clase para asignar una clase de permiso a las acciones ''crear'', ''lista'', ''recuperar'', ''actualizar'', ''eliminar''? Intento hacerlo para tener una clase que pueda reutilizarse para diferentes tablas que tengan el mismo patrón de permisos.
Tal vez me estoy ahogando en una pulgada de agua, gracias por sus respuestas.
En la documentación DRF,
Nota: el método has_object_permission a nivel de instancia solo se llamará si las comprobaciones has_permission a nivel de vista ya han pasado
Asumamos el siguiente permiso sobre user
objeto de user
- Lista: solo personal
- Crear: cualquiera
- Recuperar: propio o personal
- Actualización, actualización parcial: propia o personal
- Destruir: solo personal
permissons.py
from rest_framework import permissions
class UserPermission(permissions.BasePermission):
def has_permission(self, request, view):
if view.action == ''list'':
return request.user.is_authenticated() and request.user.is_admin
elif view.action == ''create'':
return True
elif view.action in [''retrieve'', ''update'', ''partial_update'', ''destroy'']:
return True
else:
return False
def has_object_permission(self, request, view, obj):
# Deny actions on objects if the user is not authenticated
if not request.user.is_authenticated():
return False
if view.action == ''retrieve'':
return obj == request.user or request.user.is_admin
elif view.action in [''update'', ''partial_update'']:
return obj == request.user or request.user.is_admin
elif view.action == ''destroy'':
return request.user.is_admin
else:
return False
vistas.py
from .models import User
from .permissions import UserPermission
from .serializers import UserSerializer
from rest_framework import viewsets
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
permission_classes = (UserPermission,)
EDITAR
Para Django 2.0, reemplace is_authenticated()
con is_authenticated
. El método se ha convertido en un atributo.
Las vistas basadas en clase de RestFramework tienen métodos para cada verbo HTTP (es decir, HTTP GET => view.get () etc.). Solo tiene que usar los permisos, usuarios, grupos y decoradores de django.contrib.auth como se documenta.
Personalmente odio este tipo de permisos personalizados de Frankenmonster, en mi opinión, no es muy idiomático cuando se trata del marco de Django; Así que se me ocurrió la siguiente solución: es muy similar a cómo @detail_route
decoradores @list_route
y @detail_route
. Confiamos en el hecho de que los métodos / funciones son objetos de primera clase.
En primer lugar estoy creando tal decorador:
decorators.py
def route_action_arguments(**kwargs):
"""
Add arguments to the action method
"""
def decorator(func):
func.route_action_kwargs = kwargs
return func
return decorator
Como puede ver, agrega un diccionario a la función que decora con los parámetros pasados como lista arg
Ahora creé tal mixin: mixins.py
class RouteActionArgumentsMixin (object):
"""
Use action specific parameters to
provide:
- serializer
- permissions
"""
def _get_kwargs(self):
action = getattr(self, ''action'')
if not action:
raise AttributeError
print(''getting route kwargs for action:'' + action)
action_method = getattr(self, action)
kwargs = getattr(action_method, ''route_action_kwargs'')
print(dir(kwargs))
return kwargs
def get_serializer_class(self):
try:
kwargs = self._get_kwargs()
return kwargs[''serializer'']
except (KeyError, AttributeError):
return super(RouteActionArgumentsMixin, self).get_serializer_class()
def get_permissions(self):
try:
kwargs = self._get_kwargs()
return kwargs[''permission_classes'']
except (KeyError, AttributeError):
return super(RouteActionArgumentsMixin, self).get_permissions()
Mixin hace dos cosas; cuando se llama a get_permissions
, comprueba qué ''acción'' se ejecuta, y busca la colección permission_classes desde route_action_kwargs
asociada con viewset.action_method.route_action_kwargs
cuando se llama a get_serializer_class
, hace lo mismo y elige el serializer
de route_action_kwargs
Ahora la forma en que podemos usarlo:
@method_decorator(route_action_arguments(serializer=LoginSerializer), name=''create'')
class UserViewSet (RouteActionArgumentsMixin, RequestContextMixin, viewsets.ModelViewSet):
"""
User and profile managment viewset
"""
queryset = User.objects.all()
serializer_class = UserSerializer
@list_route(methods=[''post''])
@route_action_arguments(permission_classes=(AllowAny,), serializer=LoginSerializer)
def login(self, request):
serializer = self.get_serializer_class()(data=request.data)
Para las rutas personalizadas que definimos explícitamente, podemos establecer los @route_action_arguments
explícitamente en el método.
En términos de conjuntos de vistas y métodos genéricos, todavía podemos agregarlos usando @method_decorator
@method_decorator(route_action_arguments(serializer=LoginSerializer), name=''create'')
class UserViewSet (RouteActionArgumentsMixin, RequestContextMixin, viewsets.ModelViewSet):
Puede crear una clase de permiso personalizada extendiendo el BasePermission
de DRF.
Implementa has_permission
donde tiene acceso a los objetos de request
y view
. Puede verificar request.user
para el rol apropiado y devolver True
/ False
según corresponda.
Eche un vistazo a la clase IsAuthenticatedOrReadOnly proporcionada (y otras) para obtener un buen ejemplo de lo fácil que es.
Espero que eso ayude.