AI웹 개발자 과정 공부 (팀스파르타)/프로젝트

24.05.09_TIL ( 팀 프로젝트 : 스파르타 뉴스 Django ) _ 3. 대댓글 구현 & 오류수정

티아(tia) 2024. 5. 9. 12:43
728x90

 

 

[ 두번째 프로젝트 ] 

 

 

스파르타 뉴스를 만들어 보자.

 

 

 

 

++  팀 스로젝트로 팀과의 협업이 중요하다.

++  장고 공식 문서는 항상 확인하기 

https://docs.djangoproject.com/en/4.2/

 

 

https://github.com/1489ehdghks/spartaNews

 

GitHub - 1489ehdghks/spartaNews

Contribute to 1489ehdghks/spartaNews development by creating an account on GitHub.

github.com

 

 

 

 

 

 

1.  대댓글 구현해보자.

  •  articles 에서 urls.py 추가해주기
path( # 대댓글 조회하기
        "comments/<int:comment_id>/reply/", 
        views.CommentReplyAPIView.as_view(), 
        name="comment_reply"
    ),
    path( # 대댓글 삭제하기
        "comments/<int:parent_comment_id>/replies/<int:reply_id>/", 
        views.CommentReplyDetailAPIView.as_view(), 
        name="comment_reply_detail"
        ),

 

 

 

  • articles 에서 models.py 에 대댓글을 상속받을 부모댓글 추가하기
class Comment(models.Model):
    article = models.ForeignKey(Article, on_delete=models.CASCADE, related_name="comments")
    content = models.TextField()
    # 작성자 필드 추가
    user_id = models.ForeignKey(User, on_delete=models.CASCADE)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    parent_comment = models.ForeignKey('self', on_delete=models.CASCADE, null=True, blank=True, related_name='replies')

    class Meta:
        db_table = 'comments'

 

 

 

  • articles 의serializers.py 수정하기
from rest_framework import serializers
from .models import Article, Comment, ArticleLike

class ReplySerializer(serializers.ModelSerializer):
    class Meta:
        model = Comment
        fields = "__all__"

class CommentSerializer(serializers.ModelSerializer):
    # 대댓글 표시
    replies = ReplySerializer(many=True, read_only=True)
    class Meta:
        model = Comment
        fields = "__all__"
        read_only_fields = ("article",)

    # 댓글에 article 표시 없앰
    def to_representation(self, instance):
        ret = super().to_representation(instance)
        ret.pop("article")
        return ret

class ArticleSerializer(serializers.ModelSerializer) :
    class Meta :
        model = Article
        fields = '__all__'

class ArticleDetailSerializer(ArticleSerializer):
    like_count = serializers.IntegerField(read_only = True)
    # 댓글 수 표시 
    comments_count = serializers.IntegerField(source="comments.count", read_only=True)
    comments = CommentSerializer(many = True, read_only = True)
    # 대댓글 표시
    replies = ReplySerializer(many=True, read_only=True)

class ArticleLikeSerializer(serializers.ModelSerializer) :
    class Meta :
        model = ArticleLike
        fields = "__all__"

    def to_representation(self, instance):
        representation = super().to_representation(instance)
        representation['like_count'] = instance.like_count.count()
        return representation

 

 

 

 

 

  • articles 의 view.py 추가해주기
from .serializers import ArticleDetailSerializer, ArticleSerializer, CommentSerializer, ReplySerializer

...

class CommentReplyAPIView(APIView):
    # 대댓글 조회하기
    def get(self, request, parent_comment_id, reply_id):
        parent_comment = get_object_or_404(Comment, pk=parent_comment_id)
        reply = get_object_or_404(parent_comment.replies.all(), pk=reply_id)
        serializer = CommentSerializer(reply)
        return Response(serializer.data)

    # 대댓글 생성하기
    def post(self, request, parent_comment_id):
        parent_comment = get_object_or_404(Comment, pk=parent_comment_id)
        serializer = CommentSerializer(data=request.data)
        if serializer.is_valid(raise_exception=True):
            serializer.save(article=parent_comment.article, parent_comment=parent_comment)
            return Response(serializer.data, status=status.HTTP_201_CREATED)

class CommentReplyDetailAPIView(APIView):
    # 대댓글 삭제하기
    def delete(self, request, parent_comment_id, reply_id):
        parent_comment = get_object_or_404(Comment, pk=parent_comment_id)
        reply = get_object_or_404(parent_comment.replies.all(), pk=reply_id)
        reply.delete()
        return Response(status=status.HTTP_200_OK)
    
    # 대댓글 수정하기
    def put(self, request, parent_comment_id, reply_id):
        parent_comment = get_object_or_404(Comment, pk=parent_comment_id)
        reply = get_object_or_404(parent_comment.replies.all(), pk=reply_id)
        serializer = CommentSerializer(reply, data=request.data, partial=True)
        if serializer.is_valid(raise_exception=True):
            serializer.save()
            return Response(serializer.data)

 

 

 

 

 

 

 

2.  포스트맨으로 확인작업

 

  • 슈퍼아이디를 만들어서 테스트 해보자.
  • python manage.py createsuperuser

 

 

 

  • 데이터 생성하기 먼저 seed를 쓸 수 있게 장고파일을 깔아주자.
pip install django-seed

 

그 다름으로 freeze 해준다.

pip freese > reqirements.txt

 

 

 

  • seeding 해보자.
python manage.py seed articles --number=30

 

 

 

  • django seed를 특정 article 에 댓글을 20개 생성해보자.
python manage.py seed articles --number=20 --seeder "Comment.article_id" 2

 

 

 

 

 

 

 

 

 

 

3.  포스트맨으로 확인작업 후 코드 수정

 

  • articles 의 models.py 에서 Article가 맨 위로 와야해서 순서 변경
from django.db import models
from django.conf import settings

class Article(models.Model) :
    title = models.CharField(max_length=50)
    content = models.TextField()
    url = models.URLField()
    create_at = models.DateTimeField(auto_now_add=False)
    updated_at = models.DateTimeField(auto_now=False)
    user_id = models.ForeignKey(
        settings.AUTH_USER_MODEL, 
        on_delete=models.CASCADE,
        related_name = 'articles')

class ArticleLike(models.Model) :
    article = models.ForeignKey(Article, on_delete=models.CASCADE, related_name="article_likes")
    user_id = models.ForeignKey(
        settings.AUTH_USER_MODEL, 
        on_delete=models.CASCADE, 
        related_name="user_likes")
    like_count =models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name = 'likes',
        default=0
        )

class Comment(models.Model):
    article = models.ForeignKey(Article, on_delete=models.CASCADE, related_name="comments")
    content = models.TextField()
    # 작성자 필드 추가
    user_id = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    parent_comment = models.ForeignKey('self', on_delete=models.CASCADE, null=True, blank=True, related_name='replies')

    class Meta:
        db_table = 'comments'

 

 

 

 

 

 

  • articles 의 serializers.py 에서 Reply와 Comment 부분 수정
from rest_framework import serializers
from .models import Article, Comment, ArticleLike

class ReplySerializer(serializers.ModelSerializer):
    class Meta:
        model = Comment
        fields = "__all__"
        read_only_fields = ("article",)

class CommentSerializer(serializers.ModelSerializer):
    # 대댓글 표시
    replies = ReplySerializer(many=True, read_only=True)
    class Meta:
        model = Comment
        fields = "__all__"
        read_only_fields = ("article",)

    # 댓글에 article 표시 없앰
    def to_representation(self, instance):
        ret = super().to_representation(instance)
        ret.pop("article")
        return ret

class ArticleSerializer(serializers.ModelSerializer) :
    class Meta :
        model = Article
        fields = '__all__'

class ArticleDetailSerializer(ArticleSerializer):
    like_count = serializers.IntegerField(read_only = True)
    # 댓글 수 표시 
    comments_count = serializers.IntegerField(source="comments.count", read_only=True)
    comments = CommentSerializer(many = True, read_only = True)
    # 대댓글 표시
    replies = ReplySerializer(many=True, read_only=True)

class ArticleLikeSerializer(serializers.ModelSerializer) :
    class Meta :
        model = ArticleLike
        fields = "__all__"

    def to_representation(self, instance):
        representation = super().to_representation(instance)
        representation['like_count'] = instance.like_count.count()
        return representation

 

 

 

 

  • urls.py 는 생성하는 부분만 따로 주고 조회, 수정, 삭제하는 부분 path를 나누어줌
path( # 대댓글 생성하기
        "comments/<int:comment_id>/reply/", 
        views.CommentReplyAPIView.as_view(), 
        name="comment_reply"
    ),
path( # 대댓글 조회, 수정, 삭제하기
    "comments/<int:parent_comment_id>/replies/<int:reply_id>/", 
    views.CommentReplyDetailAPIView.as_view(), 
    name="comment_reply_detail"
    ),

 

 

 

 

  • views.py는 대댓글은 조회, 생성, 수정, 삭제가 다 안되서 바꾸어주었다.
class CommentListAPIView(APIView):
  # 댓글 조회하기
    def get(self, request, article_id):
        article = get_object_or_404(Article, pk=article_id)
        comments = article.comments.all()
        serializer = CommentSerializer(comments, many=True)
        return Response(serializer.data)
  
  # 댓글 생성하기
    def post(self, request, article_id):
        article = get_object_or_404(Article, pk=article_id)
        serializer = CommentSerializer(data=request.data)
        if serializer.is_valid(raise_exception=True):
            serializer.save(article=article)
            return Response(serializer.data, status=status.HTTP_201_CREATED)

class CommentDetailAPIView(APIView):
  # 댓글 삭제하기
    def delete(self, request, comment_id):
        comment = get_object_or_404(Comment, pk=comment_id)
        comment.delete()
        data = {"id": f"{comment_id} is deleted."}
        return Response(data, status=status.HTTP_200_OK)

  # 댓글 수정하기
    def put(self, request, comment_id):
        comment = get_object_or_404(Comment, pk=comment_id)
        serializer = CommentSerializer(comment, data=request.data, partial=True)
        if serializer.is_valid(raise_exception=True):
            serializer.save()
            return Response(serializer.data)


class CommentReplyAPIView(APIView):
    # 대댓글 생성하기
    def post(self, request, comment_id):
        parent_comment = get_object_or_404(Comment, pk=comment_id)
        serializer = ReplySerializer(data=request.data)
        if serializer.is_valid(raise_exception=True):
            serializer.save(article=parent_comment.article, parent_comment=parent_comment)
            return Response(serializer.data, status=status.HTTP_201_CREATED)

class CommentReplyDetailAPIView(APIView):
  # 대댓글 조회하기
    def get(self, request, parent_comment_id, reply_id):
        parent_comment = get_object_or_404(Comment, pk=parent_comment_id)
        reply = get_object_or_404(parent_comment.replies.all(), pk=reply_id)
        serializer = ReplySerializer(reply)
        return Response(serializer.data)

    # 대댓글 삭제하기
    def delete(self, request, parent_comment_id, reply_id):
        parent_comment = get_object_or_404(Comment, pk=parent_comment_id)
        reply = get_object_or_404(parent_comment.replies.all(), pk=reply_id)
        reply.delete()
        return Response(status=status.HTTP_200_OK)
    
    # 대댓글 수정하기
    def put(self, request, parent_comment_id, reply_id):
        parent_comment = get_object_or_404(Comment, pk=parent_comment_id)
        reply = get_object_or_404(parent_comment.replies.all(), pk=reply_id)
        serializer = ReplySerializer(reply, data=request.data, partial=True)
        if serializer.is_valid(raise_exception=True):
            serializer.save()
            return Response(serializer.data)

 

 

 

 

 

 

 

 

 

 

4.  참고 블로그

 

 

https://yesjiwon5304.tistory.com/33

 

[Django] 댓글, 대댓글, 페이지네이션 구현하기

제가 [원티드 X 위코드] 프리온보딩 코스에 참여하면서, 댓글 대댓글 , 페이지네이션 기능을 구현해볼 기회가 생겼어요. 기능 구현하면서 배웠던 부분들을 정리해보려고 합니다! 시작할게요 :)

yesjiwon5304.tistory.com

 

https://devvvyang.tistory.com/48

 

[Django] 인스타그램 클론 코딩(7) - 대댓글 기능 구현

[이전 글] [Django] 인스타그램 클론 코딩(6) - 팔로우(follow) 기능 구현 [Django] 인스타그램 클론 코딩(6) - 팔로우(follow) 기능 구현 [이전 글] [Django] 인스타그램 클론 코딩(5) - 좋아요(Like) 기능 구현 [Dja

devvvyang.tistory.com

 

https://velog.io/@fall031/TIL-40.-Django-%EB%8C%93%EA%B8%80%EB%8C%80%EB%8C%93%EA%B8%80-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0

 

TIL 40. Django 댓글/대댓글 구현하기

Django를 이용하여 게시판의 댓글/대댓글 구현을 하였습니다.먼저 아래과 같이 모델링을 하였습니다.대댓글도 결국 댓글이므로 자기 class를 참조하여 parent_comment가 없을 경우 댓글이고, 있을 경우

velog.io

 

https://velog.io/@rlagurwns112/django-%EB%8C%80%EB%8C%93%EA%B8%80-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0

 

django 대댓글 구현하기

기본적으로 대댓글은 comment모델과 외래키로 연결해서 구현한다. comment모델 자체에 스스로 외래키를 걸거나 대댓글 모델을 새로 만드는 방법이 있는데 후자의 방법으로 구현했다. 아티클에 외래

velog.io

 

 

 

 

 

반응형