Chapter 6-4 Django 블로그에 댓글 기능 추가하기

2025. 5. 9. 10:07·Django

💬 Chapter 06. Django 블로그에 댓글 기능 추가하기


🎯 목표

블로그 상세 페이지에 댓글 기능을 구현하여 사용자와의 양방향 소통 기능을 구축합니다. 모델 정의부터 템플릿 반영, CBV 기반 뷰 구성까지 전반적인 흐름을 따라갑니다.


1️⃣ 댓글 모델 정의하기 (models.py)

✅ 흐름 설명

  • Comment 모델을 만들어 Blog 모델과 연결 (ForeignKey)
  • TimestampModel을 상속받아 created_at, updated_at 자동 생성
  • 작성자(User)도 ForeignKey로 연결
class Comment(TimestampModel):
    blog = models.ForeignKey(Blog, on_delete=models.CASCADE)
    content = models.CharField('본문', max_length=255)
    author = models.ForeignKey(User, on_delete=models.CASCADE)

    def __str__(self):
        return f'{self.blog.title} 댓글'

    class Meta:
        verbose_name = '댓글'
        verbose_name_plural = '댓글 목록'
        ordering = ['-created_at', '-id']  # 최신순 정렬

2️⃣ 추상 모델: TimestampModel

✅ 코드 재사용을 위한 부모 클래스 정의 (utils/models.py)

class TimestampModel(models.Model):
    created_at = models.DateTimeField('작성일자', auto_now_add=True)
    updated_at = models.DateTimeField('수정일자', auto_now=True)

    class Meta:
        abstract = True

이 클래스를 상속하면 모든 모델에 작성일자/수정일자가 자동 추가됩니다.


3️⃣ 마이그레이션 적용

python manage.py makemigrations
python manage.py migrate

4️⃣ Admin에서 댓글 관리하기 (admin.py)

✅ CommentInline으로 블로그 상세에서 댓글 관리

class CommentInline(admin.TabularInline):
    model = Comment
    fields = ['content', 'author']
    extra = 1

@admin.register(Blog)
class BlogAdmin(admin.ModelAdmin):
    inlines = [CommentInline]

admin.site.register(Comment)

5️⃣ 댓글 입력 폼 만들기 (forms.py)

class CommentForm(forms.ModelForm):
    class Meta:
        model = Comment
        fields = ('content',)
        widgets = {
            'content': forms.TextInput(attrs={'class': 'form-control'})
        }
        labels = {
            'content': '댓글'
        }

6️⃣ 댓글 출력 및 입력 템플릿 구성 (blog_detail.html)

✅ 로그인한 사용자만 댓글 작성 가능

✅ 하단에 댓글 목록 출력 ( 본문과 목록 중간에 넣기)

{% if request.user.is_authenticated %}
  <form method="post">
    {% csrf_token %}
    {{ comment_form.as_p }}
    <div class="text-end">
      <button class="btn btn-primary">작성</button>
    </div>
  </form>
{% endif %}

<div>
  {% for comment in blog.comment_set.all %}
    <div>
      {{ comment.content }}
      <p class="text-end">
        <small>{{ comment.created_at|date:'Y-m-d H:i' }} | {{ comment.author.username }}</small>
      </p>
    </div>
  {% endfor %}
</div>

7️⃣ 댓글 저장 로직 - 기존 BlogDetailView 수정

class BlogDetailView(DetailView):
    model = Blog
    queryset = Blog.object.all().prefetch_related('comment_set', 'comment_set__author')
    template_name = 'blog_detail.html'
    

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['comment_form'] = CommentForm()
        return context

    def post(self, *args, **kwargs):
        comment_form = CommentForm(self.request.POST)
        if not comment_form.is_valid():
            self.object = self.get_object()
            context = self.get_context_data(object=self.object)
            context['comment_form'] = comment_form
            return self.render_to_response(context)

        if not self.request.user.is_authenticated:
            raise Http404

        comment = comment_form.save(commit=False)
        comment.blog_id = self.kwargs['pk']
        comment.author = self.request.user
        comment.save()

        return HttpResponseRedirect(reverse_lazy('blog:detail', kwargs={'pk': self.kwargs['pk']}))

 

Models.py 에 댓글 순서 설정

 class Meta:
        verbose_name = '댓글'
        verbose_name_plural = '댓글 목록'
        ordering = ('-created_at', '-id')

8️⃣ 별도 View로 댓글 생성하기 (CommentCreateView)

✅ 로그인한 사용자만 접근 가능

✅ DetailView와 역할 분리

class CommentCreateView(LoginRequiredMixin, CreateView):
    model = Comment
    form_class = CommentForm

    def get(self, *args, **kwargs):
        raise Http404

    def form_valid(self, form):
        blog = self.get_blog()
        self.object = form.save(commit=False)
        self.object.author = self.request.user
        self.object.blog = blog
        self.object.save()
        return HttpResponseRedirect(reverse('blog:detail', kwargs={'pk': blog.pk}))

    def get_blog(self):
        pk = self.kwargs['blog_pk']
        return get_object_or_404(Blog, pk=pk)

9️⃣ URL 연결 (urls.py)

path('comment/create/<int:blog_pk>/', cb_views.CommentCreateView.as_view(), name='comment_create')

9️⃣ .forms.py 에 url 연결

<form method="post" action="{% url 'blog:comment_create' blog.pk %}">

✅ 최종 요약

  • Comment 모델과 TimestampModel로 댓글 기본 구조 생성
  • CommentForm과 CBV 기반 View 구현으로 입력 처리
  • 템플릿에서 인증된 사용자만 댓글 작성 가능하게 설정
  • 관리자 페이지에서도 댓글 관리 가능

👉 다음 단계에서는 댓글 수정/삭제 기능을 추가하거나, 비동기(AJAX) 적용으로 확장할 수 있습니다!

 

 

 

 

 

 

 

'Django' 카테고리의 다른 글

Chapter 7-1 Django 블로그 이미지 업로드 기능 만들기  (0) 2025.05.11
Chapter 6-5 댓글 페이지네이션 구현하기 (ListView + Bootstrap)  (0) 2025.05.09
Chapter 6-3 댓글 기능 시작하기 - 모델과 관리자 설정  (0) 2025.05.09
Chapter 6-2 Bootstrap 적용으로 블로그 UI 개선하기  (0) 2025.05.09
Chapter 6-1 [블로그] 댓글 기능 만들기 - Static Files 설정과 Bootstrap 적용  (0) 2025.05.09
'Django' 카테고리의 다른 글
  • Chapter 7-1 Django 블로그 이미지 업로드 기능 만들기
  • Chapter 6-5 댓글 페이지네이션 구현하기 (ListView + Bootstrap)
  • Chapter 6-3 댓글 기능 시작하기 - 모델과 관리자 설정
  • Chapter 6-2 Bootstrap 적용으로 블로그 UI 개선하기
Chansman
Chansman
안녕하세요! 코딩을 시작한 지 얼마 되지 않은 초보 개발자 찬스맨입니다. 이 블로그는 제 학습 기록을 남기고, 다양한 코딩 실습을 통해 성장하는 과정을 공유하려고 합니다. 초보자의 눈높이에 맞춘 실습과 팁, 그리고 개발하면서 겪은 어려움과 해결 과정을 솔직하게 풀어내려 합니다. 함께 성장하는 개발자 커뮤니티가 되기를 바랍니다.
  • Chansman
    찬스맨의 프로그래밍 스토리
    Chansman
  • 전체
    오늘
    어제
    • 분류 전체보기 (784) N
      • Python (32)
      • 프로젝트 (107) N
      • 과제 (25)
      • Database (40)
      • 멘토링 (11)
      • 특강 (37)
      • 기술블로그 (41)
      • 기술블로그-Fastapi편 (33)
      • 기술블로그-Django편 (153)
      • 기술블로그-Flask편 (36)
      • AI 분석 (5)
      • HTML & CSS (31)
      • JavaScript (17)
      • AWS_Cloud (21)
      • 웹스크래핑과 데이터 수집 (14)
      • Flask (42)
      • Django (77)
      • Fastapi (16)
      • 연예 (14)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    youngprofessionals
    btscomeback
    remittance
    chinanightlife
    global politics
    btsreunion
    classaction
    americaparty
    urbantrends
    RM
    bts
    btsdischarge
    titaniumcase
    chatgpterror
    americanlaw
    hotcoffeecase
    life reflection
    livebroadcast
    뷔
    btsjungkook
    smartphonedurability
    trumpmuskclash
    gpterror
    newpoliticalparty
    travel ban
    college reunions
    basalcellcarcinoma
    self-growth
    homebartrend
    lawsuitculture
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
Chansman
Chapter 6-4 Django 블로그에 댓글 기능 추가하기
상단으로

티스토리툴바