[DRF] tutorial 코드에 회원가입 기능 추가하기

azzurri21·2022년 2월 10일
0

Django REST framework

목록 보기
1/1

Django REST framework tutorial 진행 중 스스로 기획하여 추가한 기능을 소개한다.

[기능 완성 소스] : https://github.com/jseop-lim/drf-tutorial/tree/a83c8bda59590dce0c40add9efb1457d6803321a

[리팩토링 소스] : https://github.com/jseop-lim/drf-tutorial/tree/f29b2166f63ba4fa7890d81d32103cf8132f7c0f

서론

Django REST framework Tutorial 4: Authentication & Permissions에서는 UserSerializer를 정의하고 User Model과 Snippet Model을 외래키로 연결한다. 이때 튜토리얼에서는 터미널에 createsuperuser 명령어를 입력하는 방식으로 User instance를 생성한다.

왜냐하면 DRF에는 login과 logout view만 구현되어 있고 회원가입 기능은 제공하지 않기 때문이다. 그리하여 API를 통해 클라이언트가 직접 User instance를 생성하는 기능을 추가해보았다.

코드

회원가입은 궁극적으로 User Model의 instance를 생성하는 과정이므로 create action에 해당한다.

클라이언트가 회원가입 URL로 ID(username)과 비밀번호(password)와 함께 POST 요청을 전달하면, Serializer는 이를 User instance로 변환하고 저장(save)하게 된다.

Serializer

[snippets\serializers.py]

class UserSerializer(serializers.ModelSerializer):
    snippets = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
    password = serializers.CharField(write_only = True)  # 추가
    
    class Meta:
        model = User
        fields = ['id', 'username', 'password', 'snippets']  # password 추가
        
    # 추가
    def create(self, validated_data):
        user = User.objects.create_user(
            username=validated_data['username'],
            password=validated_data['password'],
        )
        return user
  • 회원가입 클라이언트 요청에 포함된 비밀번호 정보를 활용하기 위해서는 UserSerializer에 비밀번호 변수가 선언되어야 한다. 이는 공개되지 않아야 하므로 write_only=True로 설정한다.
  • serializer.create() 메서드는 create view에서 serializer.save()가 실행될 때 호출되며, 모델 인스턴스를 생성하는 기능이다. 일반적으로는 MyModel.objects.create()를 사용하지만, 이러한 방식은 DB에 비밀번호가 그대로 저장되는 문제를 남긴다. 따라서 사용자 비밀번호를 암호화 하는 기능이 포함된 User.objects.create_user()를 사용한다.

View

tutorial 4의 view 추상화 수준에서는 rest_framework.generics의 Concrete View Classes를 이용하여 UserList, UserDetail views를 구현한다. 그러므로 generics.CreateAPIView를 상속받는 UserCreate view를 아래와 같이 정의한다.

[snippets\views.py]

class UserCreate(generics.CreateAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer

URL

[config\urls.py]

from django.contrib import admin
from django.urls import path, include
from snippets.views import UserCreate  # 추가

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('snippets.urls')),
    path('api-auth/', include('rest_framework.urls')),
    path('api-auth/signup/', UserCreate.as_view(), name='user_create'),  # 추가
]
  • User 모델에 대한 create action이므로 'user-list'', 'user-detail' view가 포함된 snippets\url.py에 추가하는 방안도 제안했으나, 로그인/로그아웃/회원가입 URL을 한 파일에 모아놓기 위해 전체 프로젝트의 URL 파일에 경로를 작성했다.

이후 리팩토링 과정에서 router에 의해 결국 snippets\url.py로 경로가 옮겨지긴 한다.

리팩토링

Django REST framework Tutorial 6: ViewSets & Routers에서는 ViewSet과 Router를 이용해 한 모델에 대한 여러 actions에 관한 뷰를 하나로 통합하고, router를 이용해 URL Pattern 작성을 단순화한다.

튜토리얼 상에서는 UserList와 UserDetail view를 UserViewSet으로 합친다. 튜토리얼에서 User는 read-only로 취급되기 때문에, ReadOnlyModelViewSet을 상속받아 UserViewSet을 정의한다.

View

하지만 방금 구현한 회원가입은 User create action을 포함하기 때문에 write 권한을 추가로 가지게 된다. 이를 구현하는 여러 방법이 있다.

  1. read actions(list, detail) 뿐만 아니라 모든 actions(create, update, delete 등)를 포함하는 ModelViewSet를 사용한다.
  2. ReadOnlyModelViewSet에 create action만을 추가한다.

비밀번호나 사용자 정보 변경, 회원탈퇴 등 create 이외의 action은 만들지 않을 것이므로 후자를 채택한다.

기존 ReadOnlyModelViewSet를 상속받는 뷰 클래스에 create 메서드를 추가하는 방법도 있으나, 더 짧은 코드를 위해 CreateModelMixin을 상속받는 방법을 택했다.

[snippets\views.py]

from rest_framework.mixins import CreateModelMixin
(... 생략 ...)

class UserViewSet(viewsets.ReadOnlyModelViewSet, CreateModelMixin):
    """
    This viewset automatically provides `list`, `retrieve`, and `create` actions.
    + 회원가입 추가
    (GET, POST 요청 허용)
    """
    queryset = User.objects.all()
    serializer_class = UserSerializer

[참고] rest_framework 소스코드를 보면 두 ModelViewSet의 차이는 상속받는 부모클래스에 불과하다. 따라서 후자의 방법을 택한 것이다.

class ReadOnlyModelViewSet(mixins.RetrieveModelMixin,
                           mixins.ListModelMixin,
                           GenericViewSet):
    """
    A viewset that provides default `list()` and `retrieve()` actions.
    """
    pass


class ModelViewSet(mixins.CreateModelMixin,
                   mixins.RetrieveModelMixin,
                   mixins.UpdateModelMixin,
                   mixins.DestroyModelMixin,
                   mixins.ListModelMixin,
                   GenericViewSet):
    """
    A viewset that provides default `create()`, `retrieve()`, `update()`,
    `partial_update()`, `destroy()` and `list()` actions.
    """
    pass

URL

다만, 개별 뷰 클래스가 아닌 ViewSet으로 사용자 생성 기능을 작성하면 router에 의해 자동으로 http://127.0.0.1:8000/users/에서 회원가입을 진행하게 된다. 회원가입 URI는 아래와 같다.

POST /users/
profile
파이썬 백엔드 개발자

0개의 댓글