[TIL] 파이썬 장고 프레임웍을 사용해서 API 서버 만들기 (4)

이원진·2023년 4월 27일
0

데브코스

목록 보기
14/54
post-thumbnail
post-custom-banner

학습내용


  1. User 추가하기

  2. User 관리하기

  3. Form을 사용하여 User 생성하기

  4. Serializer를 사용하여 User 생성하기

  5. User 권한 관리

  6. 상속(Inheritance)과 오버라이딩(Overriding)

  7. perform_create()

  8. POSTMAN

1. User 추가하기


  • Question 객체를 관리할 User 추가

  • polls/models.py

    ...
    class Question(models.Model):
        ...
    
        # owner라는 User 객체는 여러 개의 Question 객체를 가짐
        # User 객체에서 Question 객체를 접근할 때 "questions"라는 이름을 사용
        # owner가 삭제되면 Question 객체도 삭제(cascade)
        owner = models.ForeignKey("auth.User", related_name = "questions", on_delete = models.CASCADE, null = True)
    
    ...

2. User 관리하기


  • User에 대한 Serializer를 생성하고, view 구현

  • polls_api/serializers.py

    ...
    
    class UserSerializer(serializers.ModelSerializer):
        # User를 참조하는 Question 객체를 PrimaryKeyRelatedField로 연결
        questions = serializers.PrimaryKeyRelatedField(many = True, queryset = Question.objects.all())
    
        class Meta:
            model = User
            fields = ["id", "username", "questions"]

  • polls_api/urls.py

    ...
    
    urlpatterns = [
            ...
        path('users/', UserList.as_view()),
        path('users/<int:pk>', UserDetail.as_view()),
    ]

  • polls_api/views.py

    ...
    from polls_api.serializers import QuestionSerializer, UserSerializer
    from django.contrib.auth.models import User
    
    ...
    
    class UserList(generics.ListAPIView):
        queryset = User.objects.all()
        serializer_class = UserSerializer
    
    class UserDetail(generics.RetrieveAPIView):
        queryset = User.objects.all()
        serializer_class = UserSerializer

3. Form을 사용하여 User 생성하기


  • Django에서 제공하는 회원가입 form을 사용해 회원가입 기능 구현

  • polls/views.py

    ...
    from django.urls import reverse, reverse_lazy
    from django.views import generic
    from django.contrib.auth.forms import UserCreationForm
    
    ...
    
    class SignUpView(generic.CreateView):
        form_class = UserCreationForm
    
        # 사용자 생성 시 user-list 페이지로 이동
        success_url = reverse_lazy("user-list")
        template_name = "registration/signup.html"
    • reverse_lazy(): urls.py에 정의된 name을 사용해 URL로 이동

  • polls/urls.py

    ...
    from views import *
    
    urlpatterns = [
        ...
        path('signup/', SignUpView.as_view())
    ]
    • from lib import * vs import lib
      - from lib import *: method()와 같이 호출
      - import lib: lib.method()와 같이 호출

  • polls_api/urls.py

    ...
    
    urlpatterns = [
            ...
        path('users/', UserList.as_view(), name = "user-list"),
        ...
    ]

  • templates/registration/signup.html

    <h2>회원가입</h2>
    
    <form method = "post">
        {% {% csrf_token %} %}
    
        <!--SignUpView 클래스에 정의된 UserCreationForm을 불러와서 사용-->
        {{ form.as_p }}
    
        <button type = "submit">가입하기</button>
    
    </form>

4. Serializer를 사용하여 User 생성하기


  • 비밀번호를 검증하고, 사용자를 생성하는 로직을 구현해야 하기 때문에 UserSerializer를 사용하지 않고 별도의 RegistrationSerializer 구현

  • polls_api/serializers.py

    ...
    from django.contrib.auth.password_validation import validate_password
    
    ...
    
    class RegisterSerializer(serializers.ModelSerializer):
        # 패스워드 검증
        password = serializers.CharField(write_only = True, required = True, validators = [validate_password])
        password2 = serializers.CharField(write_only = True, required = True)
    
        def validate(self, attrs):
            if attrs["password"] != attrs["password2"]:
                raise serializers.ValidationError({"password": "두 패스워드가 일치하지 않습니다."})
    
            return attrs
    
        def create(self, validated_data):
            user = User.objects.create(username = validated_data["username"])
            user.set_password(validated_data["password"])
            user.save()
    
            return user
    
        class Meta:
            model = User
            fields = ["username", "password", "password2"]
    • password, password2 필드는 write_only이기 때문에 서버에서 응답하는 JSON 데이터에 포함 X

  • polls_api/urls.py

    ...
    
    urlpatterns = [
        ...
        path('register/', RegisterUser.as_view()),
    ]

  • polls_api/views.py

    from polls_api.serializers import *
    ...
    
    class RegisterUser(generics.CreateAPIView):
        queryset = User.objects.all()
        serializer_class = RegisterSerializer

5. User 권한 관리


  • 로그인한 사용자만 질문을 작성할 수 있고, 질문의 작성자만 해당 질문을 수정, 삭제할 수 있는 기능 구현

  • project/settings.py

    ...
    from django.urls import reverse_lazy
    
    LOGIN_REDIRECT_URL = reverse_lazy("question-list")
    LOGOUT_REDIRECT_URL = reverse_lazy("question-list")
    
    ...

  • polls_api/urls.py

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

  • polls_api/views.py

    from rest_framework import generics, permissions
    from .permission import IsOwnerOrReadOnly
    
    class QuestionList(generics.ListCreateAPIView):
        ...
        # 로그인하지 않았다면 질문 작성 불가
        permission_classes = [permissions.IsAuthenticatedOrReadOnly]
    
        # 질문 생성 시 작성자 저장
        def perform_create(self, serializer):
            serializer.save(owner = self.request.user)
    
    class QuestionDetail(generics.RetrieveUpdateDestroyAPIView):
        queryset = Question.objects.all()
        serializer_class = QuestionSerializer
    
        # 질문 작성자가 아니면 질문 수정 불가
        permission_classes = [permissions.IsAuthenticatedOrReadOnly, IsOwnerOrReadOnly]
    
    ...

  • polls_api/permissions.py

    from rest_framework import permissions
    
    class IsOwnerOrReadOnly(permissions.BasePermission):
        def has_object_permission(self, request, view, obj):
    
            # 정보를 읽는 요청은 허용
            if request.method in permissions.SAFE_METHODS:
                return True
    
            return obj.owner == request.user

6. 상속(Inheritance)과 오버라이딩(Overriding)


  • 상속: 하나의 클래스가 다른 클래스로부터 메서드와 속성을 그대로 물려받아 사용할 수 있는 기능 제공

    • 부모 클래스(= 상위 클래스): 메서드와 속성을 물려주는 클래스

    • 자식 클래스(= 하위 클래스): 메서드와 속성을 물려받는 클래스

      • 메서드를 추가하거나 오버라이딩(메서드 재정의) 할 수 있을

    • 장점

      • 코드의 재사용성 증가

      • 클래스 간의 계층 구조를 만들어 클래스들을 그룹화해서 관리 가능


7. perform_create()


  • views.py에서 각 클래스를 generics.XXXAPIView를 상속받아서 만들었기 때문에 get(), post() 등의 메서드를 정의하지 않고도 사용 가능한 것

  • Serializer.save() 메서드는 read_only인 필드도 매개변수로 사용 가능


8. POSTMAN


  • 여러 개의 요청을 저장해놨다가 다시 사용할 수 있어서 API 개발 시 유용

메모


post-custom-banner

0개의 댓글