본문 바로가기

LIKELION 9th

[멋쟁이 사자처럼] Django로 블로그 만들기3 (댓글 쓰기)

지난 이야기🌿

7주 차에는 장고(Django)에서 CRUD기능을 구현했다.

 

 

8주 차(2021.05.17-2021.05.20)

8주 차에는 프로젝트에 새 앱을 만들어 회원가입, 로그인, 로그아웃 기능을 만들었다. 그리고 모델에 Comment 클래스를 추가해 댓글 기능을 추가했다.

 

ForeignKey

댓글 기능을 알기 전 ForeignKey에 대해 알아보자. ForeignKey(외래키)란 테이블 필드 중에서 다른 테이블의 행과 식별할 수 있는 키를 의미한다.

=> 테이블과 테이블을 연결하기 위해 사용하는 키

  • ForeignKey는 model간의 1:N 관계를 나타낼 때 사용한다(게시글과 댓글 관계).
  • 1:N 중에서 N인 쪽 관계를 선언하며, 두 개의 인자를 필요로 한다(대상이 되는 클래스 및 삭제 설정).

 

장고에서의 사용 예시를 보자.

#models.py 예시
from django.db import models
from django.db.models.deletion import CASCADE

class Post(models.Model):
	···
class Comment(models.Model):
  post = models.ForeignKey(Post, on_delete=CASCADE)

* on_delete를 CASCADE로 설정하면 이와 연결된 모든 N 쪽 데이터를 삭제한다.

 

표로 나타내면 아래와 같다.

 

출처 https://076923.github.io/

* 외래키 값을 가진 테이블은 부모 테이블(Post), 외래키가 포함된 테이블을 자식 테이블(Comment)이라 한다.

 

그럼 이제 본격적으로 댓글 달기 기능을 만들어보자!

 

1. models.py

#main/models.py
from django.db import models
from django.contrib.auth.models import User
from django.db.models.deletion import CASCADE

class Write(models.Model):
    title = models.CharField(max_length=50)
    contents = models.TextField()
    updated_at = models.DateTimeField(auto_now=True) 
    user = models.ForeignKey(User, on_delete=CASCADE)

    def __str__(self):
        return self.title

class Comment(models.Model):
    post = models.ForeignKey(Write, related_name="comment", on_delete=CASCADE)
    user = models.ForeignKey(User,related_name="comment", on_delete=CASCADE)
    content = models.TextField(max_length=200)

    def __str__(self):
        return self.post.title
  • user 변수에 models.ForeignKey을 사용해 User 모델에 Write, Comment 모델을 종속
  • post 변수에는 Write 모델에 Comment 모델을 종속
  • 사용자 또는 게시글이 삭제되면 댓글도 삭제되도록 on_delete=CASCADE 사용

 

2. forms.py 

#main.forms.py
···
class CommentForm(forms.ModelForm):
    class Meta:
        model = Comment
        fields = ['content']
···

 

Meta 클래스에 Comment 모델을 넣고, content 필드를 가져다 쓰도록 설정

 

3. urls.py - views.py - templates

1) urls.py

#main/urls.py
from django.urls import path
from . import views
app_name="main"

urlpatterns = [
    path('', views.index, name='index'),
    path('create/', views.create, name='create'),
    path('detail/<int:write_id>', views.detail, name='detail'),
    path('update/<int:write_id>', views.update, name='update'),
    path('delete/<int:write_id>', views.delete, name='delete'),
    
    #추가된 부분
    path('create_comment/<int:write_id>', views.create_comment, name='create_comment'),
    path('delete_comment/<int:write_id>/<int:comment_id>', views.delete_comment, name='delete_comment'),
]

 

2) views.py

#main/views.py
from django.shortcuts import get_object_or_404, redirect, render
from .forms import WriteForm, CommentForm
from .models import Write, Comment
from django.contrib.auth.models import User

···

def detail(request, write_id):
    user = request.user
    my_write = get_object_or_404(Write, pk=write_id)
    comment_form = CommentForm()
    comments = Comment.objects.filter(post = write_id) #Comment객체에서 post가 write_id인 것들만 가져오기
    return render(request, 'detail.html', {'my_write':my_write, 'comment_form': comment_form, 'comments':comments, 'user':user})
    
···

def create_comment(request, write_id):
    if request.method == "POST":
        comment = CommentForm(request.POST) #POST 요청으로 넘어온 데이터를 CommentForm 양식에 넣고 comment 변수에 담기
        if comment.is_valid: #해당 폼이 유효한 경우 저장하고 detail.html로 돌아가기
            form = comment.save(commit=False)
            user = request.user
            form.user = User.objects.get(id=user.id) #user 필드에 값 추가
            form.post = Write.objects.get(id=write_id) #post 필드에 값 추가
            form.save()
        return redirect("main:detail", write_id)

def delete_comment(request, write_id, comment_id):
    my_comment = get_object_or_404(Comment, id=comment_id)
    my_comment.delete()
    return  redirect("main:detail", write_id)
  • 게시글 아래에 CommentForm을 띄워주기 위해 views.py의 detail 함수 수정
  • create_comment에서 commit=False을 사용해 데이터를 당장 저장시키지 않고 지연
  • form에 user, post 정보를 넣고 난 후 저장

*detail.html은 게시글 제목과 내용을 보여주는 페이지다.

 

3) detail.html

<!-- main/templates/detail.html -->
···
<body>
	···
    <h2>댓글</h2>
    
    {% if user.is_authenticated %}
    <form method="POST" action="{% url 'main:create_comment' my_write.id %}">
        {% csrf_token %}
        {{comment_form}}
    <button type="submit">댓글작성</button>
    </form>
    {%endif%}
    
    {% for comment in comments %}
    {{comment.user}}
    {{comment.content}}
    <a href="{% url 'main:delete_comment' my_write.id comment.id%}">삭제하기</a>
    <br>
    {%endfor%}
</body>
</html>
  • is_authenticated를 사용해 로그인한 유저만 댓글을 작성할 수 있도록 설정
  • views.py detail 함수에서 템플릿 변수로 담아준 comments를 for문으로 출력

 

댓글이 잘 써지는지 확인해보자!

로그인 전 detail.html
로그인 후 detail.html
댓글 작성 후 detail.html

 

 

변수가 점점 많아져서 어질어질하다😵 

길고 길었던 8주차 세션 복습도 끝끝

 


참고자료

 

Python Django 강좌 : 제 11강 - Foreign Key (1) | 076923

Django Foreign Key

076923.github.io

 

파이썬 __str__ 메쏘드

Django를 이용해 웹을 배포하려 하다가 의문이 생겼다. Django는 DB를 models.py파일을 이용, 테이블을 클래스로 만들어 쉽게 관리가 가능하다. 예시들을 찾아보다보니 클래스 말미에 아래와 같이 __str_

neung0.tistory.com

 

[Django] 폼(Form)에서 commit=False의 의미

form Commit=False Django에서 모델 Form을 다루다보면 종종 commit=False 라는 코드를 마주칠 때가 있다. 가끔씩 헷갈리는 부분이기 때문에 장고 공식문서를 통해 학습하고자 한다. save(commit=..

whatisthenext.tistory.com