【发布时间】:2019-04-19 18:29:31
【问题描述】:
我目前正在处理一个 DRF 项目,其中管理员用户、教师用户和所有者用户应该能够访问对象详细信息视图。基本上所有用户类型,除了那些不是对象所有者或教师或管理员用户的用户。我能够为每个权限实现单独的权限,但是当我需要在视图上组合这些权限时,我遇到了障碍,因为在对象级别权限之前检查了用户级别权限。因此我不能使用布尔操作数来组合它们,我必须为我的视图编写这些丑陋的权限类。
我的问题是:
如何以更简洁的方式在我的详细视图上实现这些权限,或者,是否有更简洁的方式来获取我的结果?
如您所见,我违反了 DRY,因为我有 IsAdminOrOwner 和 IsAdminOrTeacherOrOwner 权限。在我看来,您还会注意到我覆盖了 get_permissions() 以便为相应的请求方法拥有适当的权限类。欢迎任何关于这个和其他实现的 cmets,我想要批评,以便我可以改进它。
下面是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)
【问题讨论】:
-
shoten 代码提示:既然您只是使用
get和put操作,为什么不使用RetrieveUpdateAPIView而不是APIView。这样你就不需要get_object,你不必重写get,put方法。RetrieveUpdateAPIView中的所有内容都已存在 -
感谢您的提示。我一定会调查的。关于权限,您知道更好的方法吗?
标签: python django django-rest-framework django-permissions