카테고리 없음

개발 일지 6 - 댓글 기능

sorecord 2024. 8. 20. 14:54

댓글 기능을 완전히 구현을 하지 못했다. 코드를 하나하나 작성을 하다 보니까 어떤 문제가 생겼는지 감이 온다. 

하지만 5시간을 이 문제를 붙잡고 있어서 지금까지 구현한 기능에 대해 이야기를 하려고 한다.

 

댓글과 대댓글을 구현을 하려고 했다. 

계속 사람들이 서로 대화를 할 수 있게끔 댓글이 무한히 이어지게끔 구현을 하고자 했다. 

 

그래서 만든 데이터 베이스가 3가지다. comment, comment_reply, like다. like DB는 좋아요 기능을 넣기 위해서 일단 만들기만 해두었다. 오늘은 앞선 2가지 DB를 사용하였다.

 

class Comment(models.Model):
    post = models.ForeignKey(Post_information, related_name='comments', on_delete=models.CASCADE)  # 게시물과의 관계
    author = models.ForeignKey(User_information, on_delete=models.CASCADE)  # 작성자
    content = models.TextField(null=False)  # 댓글 내용
    created_at = models.DateTimeField(auto_now_add=True)  # 작성 시간
    likes = models.IntegerField(default=0)  # 좋아요 수
    
    def __str__(self):
        return f'{self.author.nickname}: {self.content[:20]}'

class Comment_Reply(models.Model):
    parent = models.ForeignKey('self', null=True, blank=True, related_name='replies', on_delete=models.CASCADE)
    
    comment = models.ForeignKey(Comment, related_name='replies', on_delete=models.CASCADE)  # 댓글과의 관계
    author = models.ForeignKey(User_information, on_delete=models.CASCADE)  # 작성자
    content = models.TextField(null=False)  # 대댓글 내용
    created_at = models.DateTimeField(auto_now_add=True)  # 작성 시간
    likes = models.IntegerField(default=0)  # 좋아요 수

    def __str__(self):
        return f'{self.author.nickname}: {self.content[:20]}'

 

이렇게 데이터 베이스의 구조를 짰다. Comment_Reply에 parent요소는 원래 존재하지 않았다. 실제로 대댓글을 작성할때까지는 문제가 발생하지 않았다. 

 

view.py에서 댓글을 저장하는 함수를 구현하고 그 값을 post_detail에 넣어서 화면에 출력이 되게끔 구현을 했다.

 

def save_comment(request, pk): #댓글 저장
    post = get_object_or_404(Post_information, pk=pk)
    print(post)
    
    print(request.POST)
    user_id = request.session.get('username')
    if request.method == 'POST':
        if 'comment_submit' in request.POST:
            
            print("save commmmmment")
            comment_form = CommentForm(request.POST)
            if comment_form.is_valid():
                new_comment = comment_form.save(commit=False)
                new_comment.author = User_information.objects.get(username=user_id)
                new_comment.post = post
                new_comment.save()
                print(new_comment)
                return redirect('post_detail', pk=pk)
            else:
                print(comment_form.errors)
                
        elif 'reply_submit' in request.POST:
            reply_form = CommentReplyForm(request.POST)
            if reply_form.is_valid():
                new_reply = reply_form.save(commit=False)
                parent_comment_id = request.POST.get('comment_id')
                print(f"Received comment_id: {parent_comment_id}")
                if parent_comment_id:
                    parent_comment = get_object_or_404(Comment, id=parent_comment_id)
                    new_reply.comment = parent_comment
                else:
                    parent_reply_id = request.POST.get('parent_reply_id')
                    
                print(f"Received parent_reply_id: {parent_reply_id}")
                parent_reply = None
                if parent_reply_id:
                    parent_reply = get_object_or_404(Comment_Reply, id=parent_reply_id)
                    # 최상위 부모 댓글을 찾는 로직
                    while parent_reply.parent:  # 부모가 있을 경우 계속 올라감
                        parent_reply = parent_reply.parent

                    # 최상위 부모 댓글을 new_reply.comment에 설정
                    new_reply.comment = parent_reply.comment 
                    # 여기서 parent_reply.comment는 최상위 부모 댓글
                    
                
                new_reply.author = User_information.objects.get(username=user_id)
                new_reply.parent = parent_reply
                new_reply.save()
    return redirect('post_detail', pk=pk)

 

처음 댓글을 작성하는 할 때 commit_submit 값이 있으면 Comment DB에 저장이 되게끔 구현을 해두었다. 대댓글은 원래 저렇게 복잡하지 않았다. 대댓글의 대댓글을 다는 과정에서 저렇게 코드가 복잡하게 꼬여 버렸다.

 

if parent_comment_id 이 부분은 댓글에 대댓글을 다는 경우 실행이 되는 조건문이다. 

대댓글이 아닌 대댓글의 대댓글을 다는 경우에는 comment_reply의 parent 값을 가져와야 했다. 대댓글의 위치를 가져와야 했다. 그게 저 아래로 쭉 적혀있는 코드이다.  

 

뜬금없이 while문이 나온 이유는 new_reply.comment 즉 comment_reply의 comment 부분이 Comment의 외래키로 연결이 되어있어서 Comment DB의 부모 값 즉, 가장 첫번째로 적힌 댓글의 값을 찾아서 가져오는 기능이다. 

 

아 여기까지 구현을 하고 이제 다 끝났다고 생각을 했다. 

 

          <ul class="comments-list">
                {% for comment in post.comments.all %}
                    
                <li>
                    <strong>{{ comment.author.nickname }}</strong> {{ comment.content }}
                    <span>{{ comment.created_at|date:"Y-m-d H:i" }}</span>
                    <span>좋아요: {{ comment.likes }}</span>
                    <button onclick="likeComment({{ comment.id }})">좋아요</button>

                    {% if  user in user_check %}
                    <!-- 대댓글 버튼 -->
                        <button onclick="toggleReplyForm({{ comment.id }},false)">대댓글</button>
                    <!-- 대댓글 작성 폼 (숨김 처리) -->
                        <div id="reply-form-{{ comment.id }}" style="display: none;">
                        <form method="post" action="{% url 'save_comment' post.pk %}">
                            {% csrf_token %}
                            <textarea name="content" placeholder="대댓글을 입력하세요." rows="2"></textarea>
                            <input type="hidden" name="comment_id" value="{{ comment.id }}">
                            <button type="submit" name="reply_submit">대댓글 작성</button>
                        </form>
                        </div>
                    {% endif %}

                    <ul class="replies-list">
                        {% for reply in comment.replies.all %}
                            <li>
                                <strong>{{ reply.author.nickname }}</strong> {{ reply.content }}
                                <span>{{ reply.created_at|date:"Y-m-d H:i" }}</span>
                                <span>좋아요: {{ reply.likes }}</span>
                                <span>{{reply.id}}</span>
                                <button onclick="likeComment({{ comment.id }})">좋아요</button>

                                {% if  user in user_check %}
                                <!-- 대댓글 버튼 -->
                                    <button onclick="toggleReplyForm({{ reply.id }},true)">대댓글</button>
                                <!-- 대댓글 작성 폼 (숨김 처리) -->
                                    <div id="reply-form-{{ reply.id }}" style="display: none;">
                                        <form method="post" action="{% url 'save_comment' post.pk %}">
                                            {% csrf_token %}
                                            <textarea name="content" placeholder="대댓글을 입력하세요." rows="2"></textarea>
                                            <input type="hidden" name="parent_reply_id" value="{{ reply.id }}">
                                            <button type="submit" name="reply_submit">대댓글 작성</button>
                                        </form>
                                    </div>
                                {% endif %}
                                
                                <ul class="replies-list" style="margin-left: 20px;">  <!-- 대댓글의 대댓글을 다시 들여쓰기 -->
                                    {% for sub_reply in reply.replies.all %}
                                        <li>
                                            <strong>{{ sub_reply.author.nickname }}</strong> {{ sub_reply.content }}
                                            <span>{{ sub_reply.created_at|date:"Y-m-d H:i" }}</span>
                                            <span>좋아요: {{ sub_reply.likes }}</span>
                                            <button onclick="likeComment({{ sub_reply.id }})">좋아요</button>
                                        </li>
                                    {% endfor %}
                                </ul>

                            </li>
                        {% endfor %}
                    </ul>

                </li>
                {% endfor %}
            </ul>
        </div>

 

대댓글의 대댓글을 구현을 하고 나니 코드가 말도 안되게 길어지기 시작했고 반복되는 부분이 너무 많다고 생각이 들었다. 

그제서야 잘 못되었음을 느꼈다. 그럼 대댓글의 대댓글의 대댓글 그 이후로 무한히 이어지게 하기 위해서는 내가 일일히 코드를 하나씩 짜주어야 한다. 

 

이건 아니라는 것을 느꼈고 방법은 잘 모르겠지만 다른 방법이 있을 것 같다. 그 코드에 대해 고민을 좀 해봐야 할 것 같다.