В настоящее время я работаю над проектом DRF, в котором пользователи Admin, пользователи Teacher и Owner должны иметь доступ к подробному представлению объектов.В основном все типы пользователей, кроме тех, кто не является владельцем объекта, учителем или администратором.Я могу реализовать отдельные разрешения для каждого, но когда мне нужно объединить эти разрешения в представлении, я сталкиваюсь с препятствиями, потому что разрешения уровня пользователя проверяются до уровня объекта.Таким образом, я не могу использовать булевы операнды для их объединения, и мне нужно написать эти уродливые классы разрешений для моих представлений.
Мой вопрос:
Как я могу реализовать эти разрешения для моего детального просмотра более чистым способом или, альтернативно, есть ли более чистый способ получения моего результата?
Как вы увидите, я нарушаю DRY, потому что у меня есть перманент IsAdminOrOwner и IsAdminOrTeacherOrOwner.На мой взгляд, вы также заметите, что я перезаписываю get_permissions (), чтобы иметь соответствующие классы разрешений для соответствующих методов запроса.Любые комментарии к этой и другим реализациям приветствуются, я хочу критиковать, чтобы я мог их улучшить.
Здесь следует permissions.py:
from rest_framework import permissions
from rest_framework.permissions import IsAdminUser
class IsOwner(permissions.BasePermission):
def has_permission(self, request, view):
return True
def has_object_permission(self, request, view, obj):
return request.user == obj
class IsTeacher(permissions.BasePermission):
def has_permission(self, request, view):
return request.user.groups.filter(
name='teacher_group').exists()
class IsAdminOrOwner(permissions.BasePermission):
def has_object_permission(self, *args):
is_owner = IsOwner().has_object_permission(*args)
#convert tuple to list
new_args = list(args)
#remove object for non-object permission args
new_args.pop()
is_admin = IsAdminUser().has_permission(*new_args)
return is_owner or is_admin
class IsAdminOrTeacherOrOwner(permissions.BasePermission):
def has_object_permission(self, *args):
is_owner = IsOwner().has_object_permission(*args)
#convert tuple to list
new_args = list(args)
#remove object for non-object permission args
new_args.pop()
is_admin = IsAdminUser().has_permission(*new_args)
is_teacher = IsTeacher().has_permission(*new_args)
return is_admin or is_teacher or is_owner
И здесь следует мое мнение:
class UserRetrieveUpdateView(APIView):
serializer_class = UserSerializer
def get_permissions(self):
#the = is essential, because with each view
#it resets the permission classes
#if we did not implement it, the permissions
#would have added up incorrectly
self.permission_classes = [IsAuthenticated]
if self.request.method == 'GET':
self.permission_classes.append(
IsAdminOrTeacherOrOwner)
elif self.request.method == 'PUT':
self.permission_classes.append(IsOwner)
return super().get_permissions()
def get_object(self, pk):
try:
user = User.objects.get(pk=pk)
self.check_object_permissions(self.request, user)
return user
except User.DoesNotExist:
raise Http404
def get(self, request, pk, format=None):
user = self.get_object(pk)
serializer = self.serializer_class(user)
return Response(serializer.data, status.HTTP_200_OK)
def put(self, request, pk, format=None):
user = self.get_object(pk)
#we use partial to update only certain values
serializer = self.serializer_class(user,
data=request.data, partial=True)
if serializer.is_valid():
serializer.save()
return Response(serializer.data,
status.HTTP_200_OK)
return Response(status=status.HTTP_400_BAD_REQUEST)