DRF Tutorial

DRF Tutorial 4: Authentication & Permissions 2

waterclean101 2023. 2. 15. 10:57

스니펫을 유저와 연결하기

현재는 스니펫을 만들면 스니펫을 만든 유저를 스니펫 인스턴스와 연결할 수 있는 방법이 없다. 유저는 serialize된 값으로 전송되지 않고 들어온 요청(request)의 속성으로만 전송되기 때문이다.

이를 처리하기 위해 스니펫 view에서 .perform_create() 메서드를 재정의하여 인스턴스 저장이 관리되는 방식을 수정하고 수신 요청 또는 요청된 URL에 있는 모든 암묵적 정보를 처리할 수 있도록 하자.

SnippetList 뷰 클래스에서 다음 메서드를 추가한다.

# snippets/views.py

class SnippetList(generics.ListCreateAPIView):
    
    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer
    permission_classes = [permissions.IsAuthenticatedOrReadOnly]
    
    def perform_create(self, serializer):
        serializer.save(owner=self.request.user)

이제 serializer의 create() 메서드에 요청의 유효성이 검사된 데이터와 함께 추가적으로 'owner' 필드가 전달된다.


시리얼라이저 업데이트하기

이제 스니펫이 스니펫을 생성한 유저와 연결되었으므로 이를 반영하도록 SnippetSerializer를 업데이트해 보자. serializers.py의 serializer 정의에 다음 필드를 추가하자:

# snippets/serializers.py

class SnippetSerializer(serializers.ModelSerializer):

    owner = serializers.ReadOnlyField(source='owner.username')

    class Meta:
        model = Snippet
        fields = ['id', 'title', 'code', 'linenos', 'language', 'style', 'owner']

Note: 내부 메타 클래스의 필드 목록에 'owner'도 추가해야 한다.

이 필드에서 source 인수는 필드를 채우는 데 사용되는 attribute를 제어하며, serialize된 인스턴스의 모든 attribute를 가리킬 수 있다. 또한 위에 표시된 점선 표기법을 사용할 수도 있는데, 이 경우 장고의 템플릿 언어에서 사용되는 것과 유사한 방식으로 주어진 attribute를 순회한다.

우리가 추가한 필드는 유형이 지정되지 않은 ReadOnlyField 클래스이며, CharField, BooleanField 등과 같이 유형이 지정된 다른 필드와는 다르다. 유형이 지정되지 않은 ReadOnlyField는 항상 읽기 전용이며 직렬화된 표현에는 사용되지만 역직렬화된 모델 인스턴스를 업데이트하는 데는 사용되지 않는다. 여기에서는 CharField(read_only=True)를 사용할 수도 있다.

 

뷰에 필요한 권한 추가하기

이제 스니펫이 사용자와 연결되었으므로 인증된 사용자만 스니펫을 만들고, 업데이트하고, 삭제할 수 있도록 하자.

REST 프레임워크에는 특정 보기에 액세스할 수 있는 사용자를 제한하는 데 사용할 수 있는 여러 가지 권한 클래스가 포함되어 있다. 이 경우 인증된 요청에는 읽기-쓰기 액세스 권한을, 인증되지 않은 요청에는 읽기 전용 액세스 권한을 부여하는 IsAuthenticatedOrReadOnly를 사용해야 한다.

먼저 view 모듈에 다음 가져오기를 추가한다.

from rest_framework import permissions

 

그 다음 SnippetList 및 SnippetDetail 뷰 클래스에 다음 속성을 추가하자.

permission_classes = [permissions.IsAuthenticatedOrReadOnly]

 

브라우저블 API에 로그인 추가하기

현재 브라우저를 열고 브라우저블 API로 이동하면 더 이상 새 스니펫을 만들 수 없다. 새 스니펫을 만들기 위해서는 사용자로 로그인해야 한다.

프로젝트의 urls.py 파일에서 URLconf를 편집하여 브라우징 가능한 API에 사용할 로그인 view를 추가하자.

파일 상단에 다음 임포트를 추가한다.

from django.urls import path, include

그리고 파일 맨 끝에 브라우저블  API에 대한 로그인 및 로그아웃 view를 포함하는 패턴을 추가한다.

urlpatterns += [
    path('api-auth/', include('rest_framework.urls')),
]

패턴의 'api-auth/' 부분은 실제로 사용하려는 URL이 무엇이든 그 URL이 될 수 있다.

이제 브라우저를 다시 열고 페이지를 새로고침하면 페이지 오른쪽 상단에 '로그인' 링크가 표시된다. 앞서 만든 사용자 중 한 명으로 로그인하면 스니펫을 만들 수 있다.

스니펫을 몇 개 만들었으면 '/users/' 엔드포인트로 이동하여 각 사용자의 '스니펫' 필드에 각 사용자와 연결된 스니펫 ID 목록이 표시되는 것을 확인하자.