Djangoでコメント機能を作る
約435日前
2021年4月17日9:57
デジタル
Django HTML
![]()
2021/4/17 投稿
Djangoを使った開発中に覚えたことを備忘録として残します。
今回はコメント機能の実装方法を記します。
記事にコメントを付ける。
このブログには投稿記事が複数あります。
それぞれの記事には専用のコメントフォームがあり、コメントを残すと記事の下にコメントとして表示されます。
![]()
実装の順序としては、
①Commentモデルをつくる
②コメントフォームをつくる
③コメントページのビューをつくる
④コメントページのhtmlをつくる
⑤その他設定
という流れで進めます。
models.pyにCommentモデルを作成しましょう。
まず前提として記事モデルが「Post」という名前で定義されているとします。
「Comment」という名前でモデルを作成しました。
コメント投稿者の名前フィールドを作成します。
次にコメント本文のフィールドを作成します。
どの記事に対するコメントなのか分かるようにします。
コメント投稿日時のフィールドも作成しておきます。
Commentモデルを管理する際にコメント1つ1つが本文の開始20文字で一覧表示されるようにします。
これでCommentモデルが完成しました。
下記コマンドでデータベースに登録します。
モデルの操作は以上です。
models.pyやviews.pyがある階層に「forms.py」というファイルを作成しましょう。
forms.pyの中にコメント入力画面でどのフィールドを記入させるか決めておきます。
CommentCreateFormという名前でフォームを作成しました。
この投稿フォームの対象となるモデルを選択します。
対象記事と投稿日時は自動で決まるようにする為、フォーム画面では表示されないようにします。
これでコメント投稿画面を作成する準備が整いました。
views.pyにコメント投稿ページのビューを作ります。
ビュー名は「CommentCreate」としました。
クラスベースビューで「CreateView」を継承しています。
ビューで表示するhtmlテンプレートを選択します。
ここではまだ未作成ですが「comment_form.html」という名前を仮入力しておきます。
htmlは3.5項で作成します。
Commentモデルをモデルとして選びます。
先ほど作ったコメントフォームを「form_class」に割り当てます。
フォームに入力された情報が正しいときに実行されます。
フォーム的には「name」と「text」のフィールドが入力された状態で投稿されていますので、form_validが動きます。
データの保存先となるCommentモデルには「target」という項目がありますので、この項目を入力してからsaveする必要があります。
まず一旦、投稿されたフォーム内容をCommentモデルインスタンスとして変数「comment」に保存します。
このとき(commit=False)としているので、実際のCommentモデルには保存されません。
commentのtarget項目が空っぽのままなので入力します。
そしてようやくCommentモデルを保存します。
保存後は記事の詳細ページに戻るようになっています。
最後に「get_context_data」の部分です。
ここではhtmlテンプレートに渡すデータを定義しています。
3.4項でちらっと出てきたhtmlテンプレートを作成します。
「comment_form.html」というファイルを作ります。
投稿フォームの出来上がりイメージ
![]()
フォームを入力して「投稿する」ボタンを押すと、該当記事のコメント欄にコメントが表示されます。
記事詳細ページのhtml例です。
views.pyの記事詳細ビューでCommentモデルを"comments"という名前で渡すことをお忘れなく。
urls.pyにコメント投稿ページへのパスを登録しておきましょう。
無事コメントページができましたか?
引き続き勉強して理解を深めたいと思います。
関連記事も参考にして下さい。
デジタル
Django HTML
改訂履歴
2021/4/17 投稿
1. 背景
Djangoを使った開発中に覚えたことを備忘録として残します。
今回はコメント機能の実装方法を記します。
2. ゴール
記事にコメントを付ける。
3. 備忘録
3.1 - やることのイメージ
このブログには投稿記事が複数あります。
それぞれの記事には専用のコメントフォームがあり、コメントを残すと記事の下にコメントとして表示されます。
実装の順序としては、
①Commentモデルをつくる
②コメントフォームをつくる
③コメントページのビューをつくる
④コメントページのhtmlをつくる
⑤その他設定
という流れで進めます。
3.2 - Commentモデル
models.pyにCommentモデルを作成しましょう。
models.py
class Comment(models.Model):
"""記事に紐づくコメント"""
name = models.CharField('名前', max_length=255, default='名無し')
text = models.TextField('本文')
target = models.ForeignKey(Post, on_delete=models.CASCADE, verbose_name='対象記事')
created_at = models.DateTimeField('作成日', default=timezone.now)
def __str__(self):
return self.text[:20]
まず前提として記事モデルが「Post」という名前で定義されているとします。
「Comment」という名前でモデルを作成しました。
class Comment(models.Model):
コメント投稿者の名前フィールドを作成します。
name = models.CharField('名前', max_length=255, default='名無し')
次にコメント本文のフィールドを作成します。
text = models.TextField('本文')
どの記事に対するコメントなのか分かるようにします。
target = models.ForeignKey(Post, on_delete=models.CASCADE, verbose_name='対象記事')「Post」モデルから記事を1つ選択するフィールドです。
コメント投稿日時のフィールドも作成しておきます。
created_at = models.DateTimeField('作成日', default=timezone.now)
Commentモデルを管理する際にコメント1つ1つが本文の開始20文字で一覧表示されるようにします。
def __str__(self):(文字数制限をしないと管理画面がカオスになる為)
return self.text[:20]
これでCommentモデルが完成しました。
下記コマンドでデータベースに登録します。
python manage.py makemigrations
python manage.py migrate
モデルの操作は以上です。
3.3 - コメントフォーム
models.pyやviews.pyがある階層に「forms.py」というファイルを作成しましょう。
forms.pyの中にコメント入力画面でどのフィールドを記入させるか決めておきます。
forms.py
from django import forms
from .models import Comment
class CommentCreateForm(forms.ModelForm):
"""コメントフォーム"""
class Meta:
model = Comment
exclude = ('target', 'created_at')
CommentCreateFormという名前でフォームを作成しました。
class CommentCreateForm(forms.ModelForm):
この投稿フォームの対象となるモデルを選択します。
model = Comment
対象記事と投稿日時は自動で決まるようにする為、フォーム画面では表示されないようにします。
exclude = ('target', 'created_at')
これでコメント投稿画面を作成する準備が整いました。
3.4 - コメントページのビュー
views.pyにコメント投稿ページのビューを作ります。
views.py
class CommentCreate(generic.CreateView):
"""コメント投稿ページのビュー"""
template_name = 'comment_form.html'
model = Comment
form_class = CommentCreateForm
def form_valid(self, form):
post_pk = self.kwargs['pk']
post = get_object_or_404(Post, pk=post_pk)
comment = form.save(commit=False)
comment.target = post
comment.save()
return redirect('post:detail', pk=post_pk)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['post'] = get_object_or_404(Post, pk=self.kwargs['pk'])
return context
ビュー名は「CommentCreate」としました。
クラスベースビューで「CreateView」を継承しています。
class CommentCreate(generic.CreateView):
ビューで表示するhtmlテンプレートを選択します。
ここではまだ未作成ですが「comment_form.html」という名前を仮入力しておきます。
htmlは3.5項で作成します。
template_name = 'comment_form.html'
Commentモデルをモデルとして選びます。
model = Comment
先ほど作ったコメントフォームを「form_class」に割り当てます。
form_class = CommentCreateForm
フォームに入力された情報が正しいときに実行されます。
def form_valid(self, form):フォーム入力画面でコメントの投稿対象記事「target」をあえて表示させていませんでしたね?
post_pk = self.kwargs['pk']
post = get_object_or_404(Post, pk=post_pk)
comment = form.save(commit=False)
comment.target = post #Postモデルのidが「post_pk」のもの=2行目の部分
comment.save()
return redirect('post:detail', pk=post_pk)
forms.py
exclude = ('target', 'created_at')
フォーム的には「name」と「text」のフィールドが入力された状態で投稿されていますので、form_validが動きます。
データの保存先となるCommentモデルには「target」という項目がありますので、この項目を入力してからsaveする必要があります。
まず一旦、投稿されたフォーム内容をCommentモデルインスタンスとして変数「comment」に保存します。
このとき(commit=False)としているので、実際のCommentモデルには保存されません。
comment = form.save(commit=False)
commentのtarget項目が空っぽのままなので入力します。
comment.target = post
そしてようやくCommentモデルを保存します。
comment.save()
保存後は記事の詳細ページに戻るようになっています。
return redirect('post:detail', pk=post_pk)"post:detail"はurls.pyのapp_nameとpathのnameの関係です。
urls.py
from django.urls import path
from . import views
app_name = 'post' #ここ
urlpatterns = [
path('<int:pk>', views.PostDetail, name='detail'), #ここ
]
最後に「get_context_data」の部分です。
ここではhtmlテンプレートに渡すデータを定義しています。
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['post'] = get_object_or_404(Post, pk=self.kwargs['pk'])
return context
3.5 - htmlテンプレート
3.4項でちらっと出てきたhtmlテンプレートを作成します。
template_name = 'comment_form.html'
「comment_form.html」というファイルを作ります。
comment_form.htmlBootstrap CSSを適用させている為、「class="○○○"」が多いですが、この部分は無くても動きます。
<div class="container col-lg-6 offset-lg-3">
<p class="titleline">{{ post.title }}</p>
<form action="" method="POST" id="comment-form">
{{ form.non_field_errors }}
{% for field in form %}
<div class="field">
{{ field.label_tag }}
{% render_field field class="form-control" %}
{{ field.errors }}
</div>
{% endfor %}
{% csrf_token %}
<div class="row my-3">
<button type="submit" class="btn btn-success col-3 offset-2">投稿する</button>
<a class="btn btn-danger col-3 offset-2" href="{% url 'post:detail' post.pk %}">キャンセル</a>
</div>
</form>
</div>
投稿フォームの出来上がりイメージ
フォームを入力して「投稿する」ボタンを押すと、該当記事のコメント欄にコメントが表示されます。
記事詳細ページのhtml例です。
{% for comment in comments %}
<div class='border-bottom'>{{ comment.name }} {{ comment.created_at }}</div><div class='mt-2'>{{ comment.text }}</div>
{% endfor %}
views.pyの記事詳細ビューでCommentモデルを"comments"という名前で渡すことをお忘れなく。
views.py
def PostDetail(request, pk):
"""Article page"""
detail = get_object_or_404(Post, pk=pk)
context = {
"detail": detail,
"comments": Comment.objects.filter(target=detail.id) #該当記事のコメントだけを渡します。
}
3.6 - その他設定
urls.pyにコメント投稿ページへのパスを登録しておきましょう。
urls.py
from django.urls import path
from . import views
app_name = 'post'
urlpatterns = [
path('', views.PostView, name='post'),
path('<int:pk>', views.PostDetail, name='detail'),
path('comment/create/<int:pk>/', views.CommentCreate.as_view(), name='comment_create'), #ここ
]
5. さいごに
無事コメントページができましたか?
引き続き勉強して理解を深めたいと思います。
関連記事も参考にして下さい。
名無し 約239日前 2021年10月30日17:10 返信する
たい名無し 約178日前 2021年12月30日13:58 返信する
添付ファイルダウンロード(views.py)初めまして。記事を参考に自分でもコメント機能を作成しようとしたのですが、ビューがクラスベースなのでコメントの拾い方が分からず、フォームも表示されない状態になってしまいます。どのようにすればよいでしょうか。
chuna 約176日前 2022年1月1日12:30
発生している問題の事象は「コメント投稿ページに投稿用のフォームが表示されない」ということでしょうか?
ファイルの中身を確認しましたが、views.pyを見た限りは特段問題が無いように感じました。
もし差し支え無ければ、forms.py、templatesフォルダの.html、models.py、urls.py等 一式をお送り頂けますと、原因を突き止めやすくなります。
chuna.technology@gmail.com 宛に直接送って頂いても問題ありませんので、宜しくお願い申し上げます。