wafflestudio/seminar-2020

get_permissions를 overriding하는 방식에 대한 질문

Opened this issue · 2 comments

user.views의 UserViewSet를 보면 get_permissions라는 메소드가 정의되어 있습니다.

class UserViewSet(viewsets.GenericViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    permission_classes = (IsAuthenticated(), )

    def get_permissions(self):
        if self.action in ('create', 'login'):
            return (AllowAny(), )
        return self.permission_classes

제가 이해한 바는 아래와 같습니다.

get_permissions 메소드를 overriding하면 viewset에서 각 request를 처리할 때 어떠한 user에게 권한을 줄 지 조절할 수 있습니다. UserViewSet에서는, create과 login은 모든 user에게 권한을 줬고(AllowAny()), 그 외의 request들은 로그인 한 user들에게만 권한을 줬습니다(IsAuthenticated()). get_permissions 메소드는 DRF의 APIView라는 class에서 get_permissions를 overriding한 것입니다. get_permissions 메소드는 permissions class object를 리턴하면 됩니다.

UserViewSet에서 get_permissionspermission_classes를 정의한 방식이 어색하다고 느껴집니다. APIViewget_permissions를 살펴보면, self.permission_classes에는 object가 아니라 class가 들어있어야 한다는 사실을 알 수 있습니다. 그러나 UserViewSet에서는 object를 넣어놓았습니다. 물론 get_permissions 메소드를 새로 정의했기 때문에 작동하는데는 문제가 없지만, 다소 어색한 구현 방식이라 느껴집니다. 아래는 제가 구현해본 UserViewSet입니다.

class UserViewSet(viewsets.GenericViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    permission_classes = (IsAuthenticated, )

    def get_permissions(self):
        if self.action in ('create', 'login'):
            return (AllowAny(), )
        return super(SeminarViewSet, self).get_permissions()

제가 이해한 내용이 맞는지, 그리고 이렇게 구현하신 이유가 있는지 궁금합니다.

@gina0605 말씀하신 것이 맞습니다. ViewSet이 상속하는 DRF의 APIView 내부를 보면, 말씀하셨듯 permission_classesobject들의 list 또는 tuple이 아닌, class들의 list 또는 tuple로 전제되어 있음을 알 수 있습니다. 실제로 이름부터 그렇구요. 제안해주신 방식 또는 공식 문서의 관련 내용에도 나와있는 것처럼 구현하는 것이 가장 정확할 것 같습니다. return [permission() for permission in permission_classes] 요런 식의 올바른 방식이 좀 안 예쁘고 번거로워보이다보니, 으레 이런 식으로 종종 쓰기도 하는데, 엄밀히는 잘못된 방식을 제가 무의식적으로 사용한 것 같습니다. 지적 감사드립니다. :)

요약: get_permissions()는 permission object들의 list 또는 tuple을 반환하는 것이 맞고, 결과적으로는 저도 그렇게 구현했기에 실제 문제는 없으나 permission_classes를 엄밀한 용법과 다르게, class의 list 또는 tuple이 아닌, object의 list 또는 tuple로 잘못 사용했습니다.

object를 사용하는 방식이 코드가 깔끔하긴 하네요. get_permissions 메소드를 지우자 TypeError가 나서 생긴 의문점이었습니다. 답변 감사합니다 :)