WIL(9주차)

김규현·2022년 10월 28일
1

📝이번주 배운 것

Django 심화 강의 1주차 ~ 4주차 까지 학습하면서 REST API를 설계 및 구현하는 방법을 배웠다.
ClassView와 Serializer를 사용해서 각 기능마다 메소드로 구분하여 스스로 로직을 구현할 수 있는 힘을 기르게 된 한 주였던 것 같다.

그리고 API를 만든 다음 포스트맨으로 간단하고 편리하게 테스트를 하는 방법과 API를 자동으로 깔끔하게 정리해주는 Swagger도 알게되었다.

백엔드에서 만든 API를 프론트에서 JS로 다루는 것은 너무 어려웠고 힘들었다..
솔직히 지금 심정으로는 JS는 프론트에서 다루는건데 왜 힘들게 배워야 하는지 아직 잘 모르겠지만
느낌이 꼭 배워두어야 할 것 같다.. 우선 백엔드에 집중을 하고 그 다음 JS나 React도 배워볼 생각이다.

개인적으로 아직 완벽히 Restful한 API를 구현한 것 같지는 않지만 pure Django를 사용했을 때 보다 훨씬 로직들이 깔끔해졌고, REST API에 대한 개념과 설계 그리고 지켜야할 Rule을 공부해야 할 것 같다.

💡개념 정리

  • Simple-jwt를 사용하여 로그인과 같은 사용자가 인증 기능을 수행하면 토큰을 생성하여 서버에 저장하지 않고 토큰 값을 사용자를 인증할 수 있는 정보를 담아 사용자의 브라우저로 전달하여
    토큰 인증 방식으로 사용자를 인증할 수 있다.

  • Serializer로 클라이언트에서 보내는 JSON 형식의 데이터를 ModelSerializer를 사용해서 모델을 기반으로 필드에 맞게 데이터를 가공하거나 DB에 저장하고, 반대로 DB에 있는 데이터를 가공 및 JSON 형식으로 변환하여 클라이언트에 전달해 줄 수 있다.

  • 클래스형 뷰를 사용해서 HTTP 메소드에 따른 처리 기능을 if문을 사용하지 않고 메소드명으로
    구분 할 수 있어서 로직을 깔끔하고 체계적으로 구현할 수 있으며 다중 상속을 받을 수 있어서 쉽게 확장하고, 재사용성이 좋아 개발 생산성을 높일 수 있다.


🚀 Serializer와 ClassView를 사용하여 기능 구현

📌 사용자(회원가입, 로그인)

 #serializers.py(회원가입)
  class UserSerializer(serializers.ModelSerializer):
      class Meta:
          model = User
          fields = " ____all____"

      def create(self, validated_data):
          user = super().create(validated_data)
          password = user.password
          user.set_password(password)
          user.save()
          return user

  #views.py(회원가입)
  class UserView(APIView):
    def post(self, request):
        serializer = UserSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response({"msg":"가입 완료!!"}, status=status.HTTP_201_CREATED)
        return Response({"msg":f"${serializer.errors}"}, status=status.HTTP_400_BAD_REQUEST)     

view에서 JSON 형식으로 들어온 post 요청을 검증하고 저장하여 Serializer가 모델을 기반으로 필드에 맞게 DB에 저장한다.

#serializers.py(로그인)
class CustomTokenObtainPairSerializer(TokenObtainPairSerializer):
    @classmethod
    def get_token(cls, user):
        token = super().get_token(user)
        token['email'] = user.email
        return token

#views.py(로그인)
class CutomTokenObtainPairView(TokenObtainPairView):
    serializer_class = CustomTokenObtainPairSerializer

로그인 기능을 수행할 url(api/token/)으로 post 요청을 보내면 CutomTokenObtainPairView가 실행되어서 serializer에서 get_token으로 user의 정보를 담아 token을 생성하고 db에 저장하지 않은 상태로 사용자에게 refresh 토큰과 access토큰을 전달한다.

📌 게시글(보기, 작성, 수정, 삭제)

#views.py
class ArticleView(APIView):
   def get(self, request): # 게시글 전체 API
       articles = Article.objects.all()
       serializer = ArticleListSerializer(articles, many=True)
       return Response(serializer.data, status=status.HTTP_200_OK)
   
   def post(self, request): # 게시글 작성 API
       serializers = ArticleCreateSerializer(data=request.data)
       if serializers.is_valid():
           serializers.save(user=request.user)
           return Response(serializers.data, status=status.HTTP_200_OK)
       else:
           return Response(serializers.errors, status=status.HTTP_400_BAD_REQUEST)

class ArticleDetailView(APIView):
   def get(self, request, article_id): # 특정 게시글 보기 API
       article = get_object_or_404(Article, id=article_id)
       serializers = ArticleSerializer(article)
       return Response(serializers.data, status=status.HTTP_200_OK)    
   
   def put(self, request, article_id): # 게시글 수정 API
           article = get_object_or_404(Article, id=article_id)
           if request.user == article.user:
               serializers = ArticleCreateSerializer(article, data=request.data)
               if serializers.is_valid():
                   serializers.save()
                   return Response(serializers.data, status=status.HTTP_201_CREATED)
               else:
                   return Response(serializers.errors, status=status.HTTP_400_BAD_REQUEST)
           else:
               return Response({"msg":"다른 사람의 게시글은 수정할 수 없습니다!"}, status=status.HTTP_403_FORBIDDEN)

	def delete(self, request, article_id): # 게시글 삭제 API
           article = get_object_or_404(Article, id=article_id)
           if request.user == article.user:
               article.delete()
               return Response({"msg":"삭제되었습니다!"}, status=status.HTTP_204_NO_CONTENT)
           else:
               return Response({"msg":"다른 사람의 게시글은 삭제할 수 없습니다!"}, status=status.HTTP_403_FORBIDDEN)

get의 경우 불러올 객체가 여러개라면 .all()로 모두 불러와서 serializer에 넣어주고, many=true로 설정한 다음 response로 serializer.data를 반환해준다.

게시글 상세와 같이 특정한 객체의 get이라면 id를 받아 불러올 객체를 정의하고 위와 동일한 로직으로 처리한다.

post의 경우 특정 객체 설정 없이 serializer에 data=request.data로 사용자가 전달한 json 데이터를 검증하여 serializer로 모델의 필드에 맞게 저장한다.

마찬가지로 댓글과 같이 특정한 객체의 post일 경우 id를 받아 serializer를 저장할 때 받은 id를 넣어 저장할 객체를 정의한다.

put의 경우 수정할 객체의 id를 받아 정의하고 나머지는 post와 동일하게 request.data를 serializer에 넣어 검증 후 저장한다.

delete는 serializer를 사용할 필요 없이 객체의 id를 받아 정의하고, 객체의 user와 request.user가 같다면 객체를 .delete()하여 db에서 삭제하면 끝이다.


📌 팔로우, 좋아요 기능 구현

class FollowView(APIView):
   def post(self, request, user_id):
       user = get_object_or_404(User, id=user_id)
       me = request.user
       if me in user.follower.all():
           user.follower.remove(me)
           return Response('팔로우 취소', status=status.HTTP_200_OK)
       else:
           user.follower.add(me)
           return Response('팔로우', status=status.HTTP_200_OK)

팔로우, 좋아요 로직은 비슷하며 user_id를 받아 특정 user를 정의하고, 나를 request.user로 정의한 다음 내가 user의 팔로워 or 게시글의 좋아요의 .all()에 없으면 DB에 add로 추가하고, 있으면 remove로 제거하여 쉽게 구현할 수 있다.

profile
웹개발 회고록

0개의 댓글