본문 바로가기
DEV/Web 개발

Web 개발 :: 파이썬 Django Rest Framework(10) _ 댓글 CRUD

by 올커 2022. 11. 3.

DRF(Django Rest Framework)(10) _ 댓글 CRUD

01. 댓글 모델 생성하기

 - 댓글 기능을 사용하기 위한 모델은 아래와 같이 생성해주었다.

# articles/models.py

class Comment(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    article = models.ForeignKey(Article, on_delete=models.CASCADE)
    content = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return str(self.content)

 - 위에서 정의한 모델에서는 article이라는 필드를 ForeignKey로 가져오고 있다. 이 때 역참조를 위해 사용하는 related_name이 따로 지정이 되어있지 않지만, 아래와 같이 "comment_set"이라는 이름이 기본적으로 추가되어있어 작성하지 않아도 사용이 가능하다.

# articles/models.py

class Comment(models.Model):
    ...
    article = models.ForeignKey(Article, on_delete=models.CASCADE, related_name="comment_set")
    ...

02. urls.py 수정하기(article_id 넣어주기)

 - 기존에 url에는 article_id를 url에 넣어주지 않았기 때문에, 아래와 같이 수정해주었다.

# articles/urls.py

from django.urls import path
from articles import views


urlpatterns = [
    path('', views.ArticleView.as_view(), name='article_view'),
    path('<int:article_id>/', views.ArticleDetailView.as_view(), name='article_detail_view'),
    path('<int:article_id>/comment/', views.CommentView.as_view(), name='comment_view'),
    path('<int:article_id>/comment/<int:comment_id>/', views.CommentDetailView.as_view(), name='comment_detail_view'),
    path('<int:article_id>/like/', views.LikeView.as_view(), name='like_view'),
]

03. 댓글 가져오기

 - 댓글 기능에 사용할 serializer도 아래와 같이 추가해주었다.

# articles/serializers.py

from .models import Article, Comment

...
class CommentSerializer(serializers.ModelSerializer):
    class Meta:
        model = Comment
        fields = '__all__'

 - 이제 댓글기능에 사용할 CommentView를 아래와 같이 작성하였다. 

# articles/views.py

from .serializers import ArticleListSerializer, ArticleSerializer, ArticleCreateSerializer, CommentSerializer

...

class CommentView(APIView):
    def get(self, request, article_id):
        article = Article.objects.get(id=article_id)
        comments = article.comment_set.all()
        serializer = CommentSerializer(comments, many=True)
        return Response(serializer.data, status=status.HTTP_200_OK)

 - 포스트 맨에서 작성된 댓글을 잘 가져오고 있는지 확인할 수 있다.


04. 댓글 생성하기

 - 댓글 생성기능을 구현하기 위해 Serializer를 아래처럼 하나 더 추가해준다.

 - 필요한 필드는 content만 가져온다. 이 때 필드가 하나만 들어갈 경우 트레일링 콤마를 꼭 뒤에 붙여주어야 String으로 인식하지 않으니 주의해야 한다.

# articles/serializers.py

class CommentCreateSerializer(serializers.ModelSerializer):
    class Meta:
        model = Comment
        fields = ('content',)

 - CommentView에 댓글 생성을 위한 post라는 함수를 정의해준다. 대부분 구성은 게시글의 post와 유사하지만, CommentCreateSerializer를 사용하는 점, Serializer를 저장할 때 article_id를 사용하는 점을 유의해준다.

# articles/views.py

...
class CommentView(APIView):
    ...

    def post(self, request, article_id):
        serializer = CommentCreateSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save(user=request.user, article_id=article_id)
            return Response(serializer.data, status.HTTP_200_OK)
        else:
            return Response(serializer.errors, stutus=status.HTTP_400_BAD_REQUEST)

 - 포스트맨으로 검증하기 위해 comments create라는 request를 만들어준다. 이 때 꼭 Headers에 Authorization 키를 아래와 같이 먼저 추가해주어야 한다. 그렇지 않으면 "Comment.user" must be a "User" instance. 라는 에러를 만나게 된다.

 - 댓글을 작성하고 Send 하면 아래와 같이 잘 동작되는 것을 확인할 수 있다.


05. 댓글 수정하기

 - 댓글 수정기능을 구현하기도 게시글 수정과 거의 동일하다. 기존 article로 되어있는 변수명들을 comment로 변경해서 불러와 기능을 구현해준다.

# articles/views.py

...
class CommentDetailView(APIView):
    def put(self, request, article_id, comment_id):
        comment = get_object_or_404(Comment, id=comment_id)
        if request.user == comment.user:
            serializer = CommentCreateSerializer(comment, data=request.data)
            if serializer.is_valid():
                serializer.save()
                return Response(serializer.data, status=status.HTTP_200_OK)
            else:
                return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
        else:
            return Response("권한이 없습니다!", status=status.HTTP_403_FORBIDDEN)

 - 포스트맨에서 comment update 리퀘스트를 put형식으로 잡아주고, 아래와 같이 Headers 셋팅을 해준다.

 - 그 다음 Send하면 수정한 내용이 잘 반영되는 것을 확인할 수 있다.


06. 댓글 삭제하기

 - 댓글 삭제 기능도 마찬가지로 게시글 삭제하기 기능의 일부를 아래와 같이 수정해주었다.

# articles/views.py

...
class CommentDetailView(APIView):
    ...

    def delete(self, request, article_id, comment_id):
        comment = get_object_or_404(Comment, id=comment_id)
        if request.user == comment.user:
            comment.delete()
            return Response(status=status.HTTP_204_NO_CONTENT)
        else:
            return Response("권한이 없습니다!", status=status.HTTP_403_FORBIDDEN)

 - 포스트맨으로 확인해보면 204 No content가 확인된다. comment request로 확인해보아도 잘 삭제되어있는 것을 확인할 수 있다.

반응형

댓글