宿題:コメントモデルを作ろう

現在、ポストモデルしかありません。 あなたの読者からいくつかのフィードバックを受け取り、彼らにコメントさせるのはどうでしょうか?

ブログにコメントモデルを作る

blog/models.pyを開き、このコードをファイルの最後に追加しましょう:
class Comment(models.Model):
post = models.ForeignKey('blog.Post', on_delete=models.CASCADE, related_name='comments')
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.ForeignKeyrelated_name引数は、ポストモデルの中からコメントにアクセスできるようにします。

データベースにモデルのテーブルを作る

今度は、コメントモデルをデータベースに追加します。 これを行うには、モデルを変更したことをDjangoに伝えなければなりません。 コマンドラインに python manage.py makemigrations blogと入力してください。 次のような出力が表示されます:
(myvenv) ~/djangogirls$ python manage.py makemigrations blog
Migrations for 'blog':
0002_comment.py:
- Create model Comment
このコマンドがblog/migrations/ディレクトリに別のマイグレーションファイルを作成したことがわかります。 コマンドラインで python manage.py migrate blogとタイプして変更を適用する必要があります。 出力は次のようになります:
(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
コメントモデルは今データベースに存在します! 管理画面でアクセスできたら素敵ですよね?

管理画面にコメントモデルを登録する

管理画面にコメントモデルを登録するため、blog/admin.pyファイルに以下の行を追加してください:
admin.site.register(Comment)
追加する位置は、この行の直下です:
admin.site.register(Post)
コメントモデルをファイルの先頭でインポートすることも忘れないようにしてください:
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/ に行くと、コメントリストにアクセスすることができ、コメントの追加と削除の機能が使えるようになります。新しいコメント機能で遊んでみましょう!

コメントを見えるようにする

blog/templates/blog/post_detail.htmlというファイルを開き、`{% endblock %}
`タグの前に、以下の行を追加してください:
<hr>
<div data-gb-custom-block data-tag="for"></div>
<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">
<p>No comments here yet :(</p>
</div>
これで投稿の詳細ページでコメントを見ることができます。
でも、コメントをもう少し良く見せられるかもしれませんね。 static/css/blog.cssファイルの一番下にいくつかのCSSを追加しましょう:
.comment {
margin: 20px 0px 20px 20px;
}
投稿一覧ページでコメントについて、訪問者に知らせることもできます。 blog/templates/blog/post_list.htmlファイルを開き、次の行を追加します:
<a href="
<div data-gb-custom-block data-tag="url" data-0='post_detail'></div>
">Comments: {{ post.comments.count }}</a>
追加したら、テンプレートは次のようになります:
<div data-gb-custom-block data-tag="extends" data-0='blog/base.html'></div>
<div data-gb-custom-block data-tag="block"></div>
<div data-gb-custom-block data-tag="for"></div>
<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'>">{{ post.title }}</a></h1>
<p>{{ post.text|linebreaksbr }}</p>
<a href="<div data-gb-custom-block data-tag="url" data-0='post_detail'>">Comments: {{ post.comments.count }}</a>
</div>
</div>
</div>

読者がコメントを書けるようにする

今は私たちのブログでコメントを見ることができますが、追加することはできません。 それを変えましょう!
blog/forms.pyを開き、以下の行をファイルの最後に追加します:
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ('author', 'text',)
コメントモデルをインポートすることを忘れないでください。以下の行を変更して:
from .models import Post
このようにします:
from .models import Post, Comment
今度は、blog/templates/blog/post_detail.htmlを開き、{% for comment in post.comments.all %}の前に以下の行を追加します:
<a class="btn btn-default" href="<div data-gb-custom-block data-tag="url" data-0='add_comment_to_post'></div>
">Add comment</a>
もし投稿詳細ページに行くと、以下のエラーが表示されます:
NoReverseMatch
私たちはそれを修正する方法を知っています! blog/urls.pyを開き、このパターンをurlpatternsに追加してください:
path('post/<int:pk>/comment/', views.add_comment_to_post, name='add_comment_to_post'),
ページを更新したら、また違うエラーが出てきます!
AttributeError
こちらのエラーを修正するために、blog/views.pyに以下のビューを追加してください:
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をファイルの先頭でインポートすることを忘れないでください:
from .forms import PostForm, CommentForm
今、詳細投稿ページで”Add Comment”というボタンが表示されています。
AddComment
しかし、そのボタンをクリックしたら、次のように表示されます:
TemplateDoesNotExist
表示されたエラーが伝えているように、テンプレートは存在していないので、blog/templates/blog/add_comment_to_post.htmlという新しいテンプレートを作り、以下のコードを追加してください:
<div data-gb-custom-block data-tag="extends" data-0='blog/base.html'></div>
<div data-gb-custom-block data-tag="block"></div>
<h1>New comment</h1>
<form method="POST" class="post-form">
<div data-gb-custom-block data-tag="csrf_token">
{{ form.as_p }}
<button type="submit" class="save btn btn-default">Send</button>
</form>
</div>
わーい! 今あなたの読者は、ブログの投稿をどう思っているかを知らせることができます!

コメントを管理する

すべてのコメントを表示する必要はありません。 ブログの所有者として、あなたはコメントを承認または削除する選択肢をおそらく望むでしょう。 それについて何かしましょう。
blog/templates/blog/post_detail.htmlを開き、以下の行を:
<div data-gb-custom-block data-tag="for"></div>
<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">
<p>No comments here yet :(</p>
</div>
このように変更してください:
<div data-gb-custom-block data-tag="for"></div>
<div data-gb-custom-block data-tag="if"></div>
<div class="comment">
<div class="date">
{{ comment.created_date }}
<div data-gb-custom-block data-tag="if"></div>
<a class="btn btn-default" href="
<div data-gb-custom-block data-tag="url" data-0='comment_remove'>"><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'>"><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">
<p>No comments here yet :(</p>
</div>
comment_remove comment_approveパターンに一致するURLがまだないので、 NoReverseMatchが表示されます。
こちらのエラーを修正するため、以下のURLパターンをblog/urls.pyに追加してください:
path('comment/<int:pk>/approve/', views.comment_approve, name='comment_approve'),
path('comment/<int:pk>/remove/', views.comment_remove, name='comment_remove'),
さて、あなたにはAttributeErrorが見えています。このエラーを修正するために、以下のビューをblog/views.pyに追加してください:
@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をインポートする必要があります:
from .models import Post, Comment
すべて動作します!私たちにできる小さな微調整があります。投稿一覧ページ(の投稿の下)には、現在、投稿が受け取ったすべてのコメントの数が表示されます。承認された コメントの数を表示するように変更しましょう。
これを修正するには、 blog/templates/blog/post_list.htmlを開き、次の行を:
<a href="
<div data-gb-custom-block data-tag="url" data-0='post_detail'></div>">Comments: {{ post.comments.count }}</a>
下記のように変更してください:
<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モデルに追加してください:
def approved_comments(self):
return self.comments.filter(approved_comment=True)
これでコメント機能は終了です! おめでとう! :-)