여름의 서재

[Django] 댓글 기능 구현하기_Comment 본문

Skill/Django

[Django] 댓글 기능 구현하기_Comment

엉아_ 2021. 10. 22. 02:03
728x90

💡 Article과 Comment는 무슨 관계일까?

: 한 게시글에 여러개의 댓글이 달릴 수 있다. 하지만 한 댓글이 여러개의 게시글에 달릴 순 없다.

즉, Article과 Comment는 1:N 관계를 가진다.

 

🔧 댓글 기능 구현하기

1. articles/models.py

: 새로운 댓글 테이블을 만들어야 한다. comment 테이블에서 ForeignKey를 이용해 관계설정을 해주자. article의 기본키를 외래키(article 필드)로 만들어준다. on_delete옵션은 게시글이 사라지면 댓글도 같이 사라지도록 하기 위해 CASCADE로 지정한다.

 

📌 on_delete 종류

1. CASCADE : ForeignKeyField가 바라보는 값이 삭제될 때 ForeignKeyField를 포함하는 모델 인스턴스(row)도 삭제된다.

2. PROTECT : ForeignKeyField가 바라보는 값이 삭제될 때 삭제가 되지않도록 ProtectedError를 발생시킨다.

3. SET_NULL : ForeignKeyField가 바라보는 값이 삭제될 때 ForeignKeyField값을 null로 바꾼다. (SET_DEFAULT)

4. SET_DEFAULT: ForeignKeyField가 바라보는 값이 삭제될 때 ForeignKeyField값을 지정된 default 값으로 바꾼다.

 

from django.db import models
from django.conf import settings

class Comment(models.Model):
    article = models.ForeignKey(Article, on_delete=models.CASCADE)
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    content = models.CharField(max_length=200)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return self.content

 

2. migrations & migrate

: DB 테이블을 변경해줬으니 migrate는 필수!!

python manage.py migrations
python manage.py migrate

 

3. articles/forms.py

: 댓글을 작성하는 폼을 커스텀해보자. 댓글 작성시 user필드와 article필드(ForeignKey)가 보이지 않도록 수정해야 한다.

from django import forms
from .models import Article, Comment

class CommentForm(forms.ModelForm):

    class Meta:
        model = Comment
        # fields = '__all__'
        exclude = ('article', 'user',)

 

4. articles/urls.py

: 댓글을 작성하고 삭제할때 쓰이는 url을 만들어준다.

from django.urls import path
from . import views

app_name = 'articles'
urlpatterns = [
	# ...생략...
    
    path('<int:pk>/comments/', views.comments_create, name='comments_create'),
    path('<int:article_pk>/comments/<int:comment_pk>/delete/', views.comments_delete, name='comments_delete'),
]

 

5. articles/views.py

 

📌 comments_create (댓글 작성 함수)

: POST 요청인지 인증이 된 사용자인지를 처리해주고, 관계를 이을 article을 불러온다.

form에 작성된 데이터가 유효한지 검사하고 유효하다면 저장해준다.

(이때, comment = comment_form.save() -> 이렇게 바로 저장하면 들어가야하는 user값과 article값이 안들어간 상황이기 때문에 에러가 난다)

 

📌 comments_delete (댓글 삭제 함수)

: 해당되는 댓글을 불러오고, 현재 user와 댓글을 작성한 user가 같다면 댓글을 삭제한다.

@require_POST
def comments_create(request, pk):
    if request.user.is_authenticated:
        article = get_object_or_404(Article, pk=pk)
        comment_form = CommentForm(request.POST)
        if comment_form.is_valid():
            comment = comment_form.save(commit=False)
            comment.article = article
            comment.user = request.user
            comment.save()
        return redirect('articles:detail', article.pk)
    return redirect('accounts:login')


@require_POST
def comments_delete(request, article_pk, comment_pk):
    if request.user.is_authenticated:
        comment = get_object_or_404(Comment, pk=comment_pk)
        if request.user == comment.user:
            comment.delete()
    return redirect('articles:detail', article_pk)

 

6. articles/detail.html

 

📌 read

: 댓글을 작성한 사람과 댓글 내용이 출력되도록 만든다.

 

📌 delete

: 현재 유저가 댓글을 작성한 유저일때만 delete 버튼(댓글 삭제 버튼)이 보이도록 만든다.

 

📌 create

: 로그인한 유저(인증된 유저)만 댓글을 작성할 수 있도록 만든다.

<!--생략-->

<h4>댓글 목록</h4>

<!--read-->
{% if comments %}
  <p><b>{{ comments|length }}개의 댓글이 있습니다.</b></p>
{% endif %}
<ul>
  {% for comment in comments %}
    <li>
      {{ comment.user }} - {{ comment.content }}
      <!--delete-->
      {% if user == comment.user %}
        <form action="{% url 'articles:comments_delete' article.pk comment.pk %}" method="POST" class="d-inline">
          {% csrf_token %}
          <input type="submit" value="DELETE">
        </form>
      {% endif %}
    </li>
  {% empty %}
    <p>댓글이 없어요..</p>
  {% endfor %}
</ul>

<hr>

<!--create-->
{% if request.user.is_authenticated %}
  <form action="{% url 'articles:comments_create' article.pk %}" method="POST">
    {% csrf_token %}
    {{ comment_form }}
    <input type="submit">
  </form>
{% else %}
  <a href="{% url 'accounts:login' %}">[댓글을 작성하려면 로그인하세요.]</a>
{% endif %}
{% endblock content %}

<!--생략-->

 

Comments