장고 Comment 기능 학습

Comment 기능 구현

Comment 기능 적용 방법 중, 현재까지 공부한 방법으로는 크게 2가지로 나뉠 수 있다.

  • 특정 앱에 comment 모델 생성하여 구현하는 방법
  • comment 앱 추가 생성하여 구현하는 방법
  • 여기서는 블로그 프로젝트를 예로 들어, comment 앱을 추가 생성하여 댓글 기능 구현 방법을 정리해보았다.

comment 앱 추가 생성하여 구현하는 방법(블로그 프로젝트)

1. comment 앱 생성

  • $ python manage.py startapp comment

2. comment 앱 모델 구현

  • 경로 : comment > models.py
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    from django.db import models
    from django.contrib.auth import get_user_model
    # Create your models here.
    from django.contrib.contenttypes.fields import GenericForeignKey
    from django.contrib.contenttypes.models import ContentType

    class Comment(models.Model):
    author = models.ForeignKey(get_user_model(), on_delete=models.CASCADE, related_name='my_comments')

    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
    object_id = models.PositiveIntegerField()
    content_object = GenericForeignKey('content_type', 'object_id')

    text = models.CharField(max_length=400)
    created = models.DateTimeField(auto_now_add=True)

    class Meta:
    ordering = ['-created']

3. comment 모델 폼 구현

  • 경로 : comment > forms.py
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    from django import forms
    from .models import Comment
    class CommentForm(forms.ModelForm):
    class Meta:
    model = Comment
    fields = ['text','content_type','object_id']
    widgets = {
    'content_type': forms.HiddenInput(),
    'object_id':forms.HiddenInput(),
    }

4. comment 모델을 관리자페이지에 등록

  • 경로 : comment > admin.py
    1
    2
    3
    4
    5
    6
    from django.contrib import admin

    # Register your models here.
    from .models import Comment

    admin.site.register(Comment)

5. blog 포스트 상세페이지 view 구현

  • 경로 : blog > views.py
    1
    2
    3
    4
    5
    6
    7
    8
    9
    class PostDetail(DetailView):
    model = Post
    template_name = 'post/post_detail.html'
    # 댓글 입력창
    def get_context_data(self, **kwargs):
    context_data = super().get_context_data(**kwargs)
    content_type = ContentType.objects.get_for_model(self.model)
    context_data['form'] = CommentForm(initial={'content_type':content_type, 'object_id':self.object.id})
    return context_data

6. blog 포스트 상세페이지 html 구현

  • 경로 : blog > templates > blog > post_detail.html
    1
    2
    3
    4
    5
    6
    7
    8
    9
    {% extends 'base.html' %}

    {% block content %}
    <div>
    <!-- comment 앱 > templatetags > comment.py 호출 -->
    {% load comment %}
    {% show_comment content_type=object object_id=object.id %}
    </div>
    {% endblock %}

7. 게시물의 comment 목록 반환해주는 페이지 생성

  • 경로 : comment > templatetags > comment.py
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    from django.template.loader import render_to_string
    from django.contrib.contenttypes.models import ContentType

    from django.template import Library
    register = Library()

    from comment.forms import CommentForm
    from comment.models import Comment

    @register.simple_tag(takes_context=True)
    def show_comment(context, content_type, object_id):
    # 폼 만들기
    content_type = ContentType.objects.get_for_model(content_type)
    form = CommentForm(initial={'content_type':content_type, 'object_id':object_id})

    # 해당 하는 댓글 목록 뽑기
    comments = Comment.objects.filter(content_type=content_type, object_id=object_id).all()

    # 템플릿 렌더링
    return render_to_string('comment/show_comment.html',{'form':form, 'object_list':comments}, request=context['request'])

8. comment 레이아웃 페이지 생성

  • 경로 : comment > templates > comment > show_comment.html
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <form action="{% url 'add_comment' %}" method="post">
    {% csrf_token %}
    {{form.as_p}}
    <input type="submit" class="btn btn-primary" value="Write">
    </form>
    <table class="table table-striped">
    {% for object in object_list %}
    <tr>
    <td>{{object.text}} {% if object.author == user %}<a href="{% url 'delete_comment' object.id %}">[삭제]</a>{% endif %}</td>
    <td>{{object.author.username}}</td>
    <td>{{object.created}}</td>
    </tr>
    {% endfor %}
    </table>

9. comment 추가/삭제 페이지로 이동하도록 url 설정

  • 경로 : comment > urls.py
    1
    2
    3
    4
    5
    6
    from django.urls import path
    from .views import *
    urlpatterns = [
    path('add_comment/', add_comment, name='add_comment'),
    path('delete_comment/<int:pk>/', delete_comment, name='delete_comment'),
    ]

10. comment 추가/삭제 뷰 코드 구현

  • 경로 : comment > views.py
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    from .forms import CommentForm
    from .models import Comment
    from django.shortcuts import redirect
    from django.contrib import messages
    def add_comment(request):
    if not request.user.is_anonymous:
    comment_form = CommentForm(request.POST)
    comment_form.instance.author_id = request.user.id
    if comment_form.is_valid():
    comment_form.save()
    messages.add_message(request, messages.SUCCESS, "댓글을 작성하였습니다.")
    else:
    messages.add_message(request, messages.WARNING, "Comment Invalid")
    else:
    messages.add_message(request, messages.WARNING, "댓글은 로그인 사용자만 남길 수 있습니다.")

    referer = request.META['HTTP_REFERER']
    return redirect(referer)

    def delete_comment(request, pk):
    comment = Comment.objects.filter(pk=pk)
    if comment.exists() and comment[0].author == request.user :
    comment.delete()
    messages.add_message(request, messages.SUCCESS, "댓글을 삭제하였습니다.")
    else:
    messages.add_message(request, messages.WARNING, "댓글을 삭제할 수 없습니다.")

    referer = request.META['HTTP_REFERER']
    return redirect(referer)