여름의 서재
[Django] 댓글 기능 구현하기_Comment 본문
💡 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 %}
<!--생략-->
'Skill > Django' 카테고리의 다른 글
[Django] 팔로우 기능 구현하기_Follow (0) | 2021.10.24 |
---|---|
[Django] 좋아요 기능 구현하기_Like (1) | 2021.10.24 |
[Django] 게시글에 User 정보 넣기_Article-User (0) | 2021.10.22 |
[Django] User model 커스텀하기 (0) | 2021.10.22 |
[Django] Auth 정복하기(3)_Update & Delete (0) | 2021.09.26 |