지금까지 Post 모델만 있었죠. 독자들에게 피드백과 코멘트를 받을 수 있는 댓글을 만들어보면 어떨까요?
blog/models.py
파일을 열어, 파일의 맨 마지막에 아래 코드를 추가해주세요.
Copy class Comment ( models . Model ):
post = models . ForeignKey ( 'blog.Post' , related_name = 'comments' , on_delete = models.CASCADE)
author = models . CharField (max_length = 200 )
text = models . TextField ()
created_date = models . DateTimeField (default = timezone.now)
approved_comment = models . BooleanField (default = False )
def approve ( self ):
self . approved_comment = True
self . save ()
def __str__ ( self ):
return self . text
각 필드 타입들에 대한 설명은 장고걸스 튜토리얼의 Django 모델 장에서 다뤘으니 다시 읽고 돌아와도 좋아요.
이번 장에서는 새로운 필드 타입을 써볼게요.
models.BooleanField - 참/거짓(true/false) 필드랍니다.
models.ForeignKey
의 related_name
옵션은 Post 모델에서 댓글에 액서스할 수 있게 합니다.
데이터베이스에 새 모델 테이블 생성하기
자, 데이터베이스에 Comment 모델을 추가할 시간이에요. 그러려면 장고에게 모델 변경내용을 알려줘야 합니다. python manage.py makemigrations blog
명령어를 입력하세요.
Copy (myvenv) ~/djangogirls$ python manage.py makemigrations blog
Migrations for 'blog':
0002_comment.py:
- Create model Comment
blog/migrations
디렉터리에 새로 마이그레이션 파일이 생성되었어요. 이제 python manage.py migrate blog
명령어로 변경내역을 적용합니다. 다음과 같은 출력이 보일 거예요.
Copy (myvenv) ~/djangogirls$ python manage.py migrate blog
Operations to perform:
Apply all migrations: blog
Running migrations:
Rendering model states... DONE
Applying blog.0002_comment... OK
이제 Comment 모델이 데이터베이스 안에 생겼네요! 관리자 패널(admin panel)에서 Commnet 모델에 접근할 수 있다면 멋지겠죠?
관리자 패널에 모델을 등록하기 위해, blog/admin.py
로 가서 아래 코드를 추가해주세요.
Copy admin . site . register (Comment)
아래 코드 바로 밑에 추가하면 됩니다.
Copy admin . site . register (Post)
파일 맨 처음에 Comment 모델을 import 하는 것을 잊지 마세요. 소스파일은 아래와 같은 내용이어야 합니다.
Copy from django . contrib import admin
from . models import Post , Comment
admin . site . register (Post)
admin . site . register (Comment)
커맨드 라인에서 python manage.py runserver
를 입력하고 브라우저에서 http://127.0.0.1:8000/admin/ 를 열어보세요. Comment 리스트가 보이고, 댓글을 추가 삭제할 수 있을 거예요. 주저하지 말고 댓글을 가지고 놀아보세요.
댓글 보여주기
blog/templates/blog/post_detail.html
로 가서 {% endblock %}
태그 바로 전에 아래 코드를 추가하세요.
Copy <hr>
<div data-gb-custom-block data-tag="for">
<div class="comment">
<div class="date">{{ comment.created_date }}</div>
<strong>{{ comment.author }}</strong>
<p>{{ comment.text|linebreaks }}</p>
</div>
<div data-gb-custom-block data-tag="empty"></div>
<p>No comments here yet :(</p>
</div>
자 이제 post_detail 페이지의 댓글을 읽을 수 있어요.
좀 더 이쁘게 보이면 좋겠어요. static/css/blog.css
파일을 열어 css
코드를 추가해보세요.
Copy .comment {
margin : 20 px 0 px 20 px 20 px ;
}
post_list 페이지에서 각 글마다 달린 댓글 개수도 보여줍시다. blog/templates/blog/post_list.html
에 아래 코드를 추가해주세요.
Copy <a href="
<div data-gb-custom-block data-tag="url" data-0='post_detail'></div>
">Comments: {{ post.comments.count }}</a>
이제 아래와 같은 코드가 될 거에요.
Copy
<div data-gb-custom-block data-tag="extends" data-0='blog/base.html'></div>
<div data-gb-custom-block data-tag="block">
<div data-gb-custom-block data-tag="for">
<div class="post">
<div class="date">
{{ post.published_date }}
</div>
<h1><a href="
<div data-gb-custom-block data-tag="url" data-0='post_detail'></div>">{{ post.title }}</a></h1>
<p>{{ post.text|linebreaksbr }}</p>
<a href="<div data-gb-custom-block data-tag="url" data-0='post_detail'></div>">Comments: {{ post.comments.count }}</a>
</div>
</div>
</div>
댓글 작성하기
방문자는 댓글을 읽을 수 있지만, 직접 댓글을 남길 수는 없어요. 댓글을 작성할 수 있게 만들어 봅시다.
blog/forms.py
파일의 맨 끝에 아래 코드를 추가하세요.
Copy class CommentForm ( forms . ModelForm ):
class Meta :
model = Comment
fields = ( 'author' , 'text' , )
파일 맨 처음에 Comment 모델을 import 하는 것을 잊지 마세요.
아래 코드를 찾아
Copy from . models import Post
이렇게 수정하세요.
Copy from . models import Post , Comment
다음으로 blog/templates/blog/post_detail.html
파일에서 {% for comment in post.comments.all %}
전에 아래 코드를 추가해주세요.
Copy <a class="btn btn-default" href="<div data-gb-custom-block data-tag="url" data-0='add_comment_to_post'></div>
">Add comment</a>
post_detail 페이지로 가면 에러가 뜰 거에요.
어떻게 고쳐야하는지 알고 있을 거에요! blog/urls.py
파일에서 urlpatterns
에 새 패턴을 추가해야죠.
Copy url ( r ' ^ post/ ( ?P<pk> \d + ) /comment/ $ ' , views.add_comment_to_post, name = 'add_comment_to_post' ),
페이지를 새로고침하면 또 에러가 보일 거에요!
에러를 해결하려면 blog/views.py
파일에서 새로운 뷰를 추가해야해요.
Copy def add_comment_to_post ( request , pk ):
post = get_object_or_404 (Post, pk = pk)
if request . method == "POST" :
form = CommentForm (request.POST)
if form . is_valid ():
comment = form . save (commit = False )
comment . post = post
comment . save ()
return redirect ( 'post_detail' , pk = post.pk)
else :
form = CommentForm ()
return render (request, 'blog/add_comment_to_post.html' , { 'form' : form})
이번에도 파일 맨 처음에 CommentForm
을 import 하는 것을 잊지 마세요.
Copy from . forms import PostForm , CommentForm
이제 post_detail 페이지로 가보면, "Add comment" 버튼을 확인할 수 있을 거에요.
하지만, 버튼을 끌릭하면 이런 게 보이겠죠.
이 에러는 뷰에서 지정된 템플릿이 없다는 에러에요. blog/templates/blog/
경로에 add_comment_to_post.html
이라는 새 파일을 만들고 아래 코드를 작성하세요.
Copy
<div data-gb-custom-block data-tag="extends" data-0='blog/base.html'></div>
<div data-gb-custom-block data-tag="block">
<h1>New comment</h1>
<form method="POST" class="post-form">
<div data-gb-custom-block data-tag="csrf_token"></div>
{{ form.as_p }}
<button type="submit" class="save btn btn-default">Send</button>
</form>
</div>
와! 이제 내 블로그 글을 읽은 사람들이 댓글을 남길 수 있게 되었네요!
댓글 관리하기
현재 블로그에 남겨진 모든 댓글들이 post_detail 페이지에 보이네요. 블로그 관리자가 댓글을 승인하거나 삭제할 수 있는 기능이 필요하겠죠. 이제 이 기능을 만들어 봅시다.
blog/templates/blog/post_detail.html
파일에서 아래 코드를 찾아
Copy
<div data-gb-custom-block data-tag="for">
<div class="comment">
<div class="date">{{ comment.created_date }}</div>
<strong>{{ comment.author }}</strong>
<p>{{ comment.text|linebreaks }}</p>
</div>
<div data-gb-custom-block data-tag="empty"></div>
<p>No comments here yet :(</p>
</div>
이렇게 바꾸세요.
Copy
<div data-gb-custom-block data-tag="for">
<div data-gb-custom-block data-tag="if">
<div class="comment">
<div class="date">
{{ comment.created_date }}
<div data-gb-custom-block data-tag="if">
<a class="btn btn-default" href="
<div data-gb-custom-block data-tag="url" data-0='comment_remove'></div>"><span class="glyphicon glyphicon-remove"></span></a>
<a class="btn btn-default" href="<div data-gb-custom-block data-tag="url" data-0='comment_approve'></div>"><span class="glyphicon glyphicon-ok"></span></a>
</div>
</div>
<strong>{{ comment.author }}</strong>
<p>{{ comment.text|linebreaks }}</p>
</div>
</div>
<div data-gb-custom-block data-tag="empty"></div>
<p>No comments here yet :(</p>
</div>
NoReverseMatch
예외가 뜰 텐데요. 이를 comment_remove
와 comment_approve
패턴에 매칭되는 url이 없기 때문이에요.
에러를 해결하려면 blog/urls.py
에 url
패턴을 추가해주세요.
Copy url ( r ' ^ comment/ ( ?P<pk> \d + ) /approve/ $ ' , views.comment_approve, name = 'comment_approve' ),
url ( r ' ^ comment/ ( ?P<pk> \d + ) /remove/ $ ' , views.comment_remove, name = 'comment_remove' ),
이제 AttributeError
에러가 또 보일 거에요. 에러를 해결하기 위해, blog/views.py
에 뷰를 추가해주세요.
Copy @login_required
def comment_approve ( request , pk ):
comment = get_object_or_404 (Comment, pk = pk)
comment . approve ()
return redirect ( 'post_detail' , pk = comment.post.pk)
@login_required
def comment_remove ( request , pk ):
comment = get_object_or_404 (Comment, pk = pk)
comment . delete ()
return redirect ( 'post_detail' , pk = comment.post.pk)
파일 맨 처음에 Comment
를 import하는 것을 잊지 않았겠죠.
Copy from . models import Post , Comment
모든 것이 잘 작동되네요! 하지만 마지막 한 가지가 남았어요. 현재 post_list 페이지에서는 등록된 모든 댓글의 개수가 보이는데요. 승인된 댓글의 개수만 보이게 수정해봅시다.
blog/templates/blog/post_list.html
파일에서 아래 코드를
Copy <a href="
<div data-gb-custom-block data-tag="url" data-0='post_detail'></div>">Comments: {{ post.comments.count }}</a>
다음과 같이 수정해주세요.
Copy <a href="<div data-gb-custom-block data-tag="url" data-0='post_detail'></div>">Comments: {{ post.approved_comments.count }}</a>
그리고 blog/models.py
파일에서 Post
모델에 아래 메서드를 추가해주세요.
Copy def approved_comments ( self ):
return self . comments . filter (approved_comment = True )
드디어 댓글 기능을 모두 만들었어요! 함께 축하해요. :-)