폼으로 댓글 기능 구현하기[2]

Posted on 2021-12-20 by GKSRUDTN99
Django로 웹사이트 만들기 Django

폼으로 댓글 기능 구현하기[2]

포스트 상세 페이지에 댓글 기능 반영하기

  • 현재는 포스트 상세 페이지의 아랫부분에 목업 형태로 댓글이 나열되어 있고, 위에는 댓글 작성창도 있다.
  • 우선, 아래 댓글들이 목업이 아니라 실제 댓글이 출력되도록 변경한다.

1. 포스트 상세 페이지의 현재 댓글 구조 확인하기

  • 댓글과 관련이 있는 부분은 post_detail.html에서 <div class="comment-area">안에 구현되어 있다.
  • class가 같은 요소는 한 HTML 문서 내에서 여러 개 등장할 수 있으므로 id="comment-area"를 div 태그에 추가할 것이다.
  • 또한 댓글 역시 각각 <div>태그로 구분되어 있지만 id는 부여되어 있지 않으므로, comment-뒤에 해당 comment의 pk를 붙이는 방식으로 id를 부여할 것이다.

2. 테스트 코드 작성하기

  • test.py를 열어 setUp() 함수 맨 끝에 댓글을 만드는 코드를 추가한다.
from django.test import TestCase, Client
from bs4 import BeautifulSoup
# 아래에서 Comment Class Import
from .models import Post, Category, Tag, Comment
from django.contrib.auth.models import User


class TestView(TestCase):
    def setUp(self):
        # (...생략...)
        self.post_003.tags.add(self.tag_python_kor)
        self.post_003.tags.add(self.tag_python)

        # 댓글 만들기
        self.comment_001 = Comment.objects.create(
            post=self.post_001,
            author=self.user_obama,
            content='첫 번째 댓글입니다'
        )
  • test_post_detail 함수의 맨 끝에 Comment를 확인하는 내용을 추가한다.
# (... 생략 ...)
    def test_post_detail(self):
        self.assertEqual(self.post_001.get_absolute_url(), '/blog/1/')
        response = self.client.get(self.post_001.get_absolute_url())
        self.assertEqual(response.status_code, 200)
        soup = BeautifulSoup(response.content, 'html.parser')
        self.navbar_test(soup)
        self.category_card_test(soup)
        self.assertIn(self.post_001.title, soup.title.text)
        main_area = soup.find('div', id='main-area')
        post_area = main_area.find('div', id='post-area')
        self.assertIn(self.post_001.title, post_area.text)
        self.assertIn(self.post_001.category.name, post_area.text)

        self.assertIn(self.post_001.author.username.upper(), post_area.text)
        self.assertIn(self.post_001.content, post_area.text)

        self.assertIn(self.tag_hello.name, post_area.text)
        self.assertNotIn(self.tag_python.name, post_area.text)
        self.assertNotIn(self.tag_python_kor.name, post_area.text)

        # comment area
        comments_area = soup.find('div', id='comment-area')
        comment_001_area = comments_area.find('div', id=f'comment-{self.comment_001.id}')
        self.assertIn(self.comment_001.author.username, comment_001_area.text)
        self.assertIn(self.comment_001.content, comment_001_area.text)
# (...생략...)

3. post_detail.html 수정하기

  • post_detail.html을 열어 댓글이 나타나는 부분을 다음과 같이 수정한다.
<!-- (...생략...) -->
<!-- Comments section-->
    <div class="mb-5" id="comment-area">
        <div class="card bg-light">
            <div class="card-body">
                <!-- Comment form-->
                <form class="mb-4"><textarea class="form-control" rows="3"
                                             placeholder="Join the discussion and leave a comment!"></textarea>
                </form>
                {% if post.comment_set.exists %}
                    {% for comment in post.comment_set.iterator %}
                        <!-- Single comment-->
                        <div class="d-flex" id="comment-{{ comment.pk }}">
                            <div class="flex-shrink-0"><img class="rounded-circle"
                                                            src="https://dummyimage.com/50x50/ced4da/6c757d.jpg"
                                                            alt="..."/></div>
                            <div class="ms-3">
                                <div class="fw-bold">{{ comment.author.username }} &nbsp;&nbsp; <small
                                        class="text-muted">{{ comment.created_at }}</small></div>
                                {{ comment.content | linebreaks }}
                            </div>
                        </div>
                    {% endfor %}
                {% endif %}
            </div>
        </div>
    </div>
  • 포스트에 댓글이 하나도 없으면 굳이 쿼리를 생성할 필요가 없으므로, 댓글의 유무를 먼저 확인한다.
  • 댓글이 있다면 for문으로 반복해서 html 코드를 만든다.
  • 댓글 본문에서 줄바꿈이 가능하도록 linebreaks를 추가한다.
  • 이제 Django Test를 실행해보면 OK가 출력된다.

4. VIEW ON SITE버튼 만들기

  • 관리자 페이지에서 댓글을 생성한 뒤 해당 댓글의 위치로 바로 이동하는 VIEW ON SITE버튼을 추가한다.
  • Comment 모델에 get_absolute_url()함수를 정의하여 해결할 수 있다.
  • models.py를 열어 다음과 같이 작성한다.
class Comment(models.Model):
    post = models.ForeignKey(Post, on_delete=models.CASCADE)
    author = models.ForeignKey(User, 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 f'{self.author}::{self.content}'

    def get_absolute_url(self):
        return f'{self.post.get_absolute_url()}#comment-{self.pk}'
  • 뒤의 #comment-{self.pk}는 html의 id를 의미한다.
  • 위와 같이 작성하면 포스트 상세페이지가 열린 뒤, 해당 id를 가진 태그로 페이지가 이동한다.
  • 이제 관리자 페이지에서 Comment 하나를 선택하면, 해당 댓글이 있는 위치로 바로 이동할 수 있다.