🌏

Python、Django でブログ実装(こつこつ③コメントを書けるようにする、ちょっとデータベースいじり)

に公開

今回は、投稿した記事にコメントを書けるようにしよーと思います!
それでは、ごー♪

前回までの記事

前回
https://zenn.dev/animalz/articles/71771ba84fc3bd
前々回
https://zenn.dev/animalz/articles/30f1cd844a57bf

前回までのプロジェクト(コード)

GitHub: https://github.com/Animalyzm/mikoto_project
今回のプロジェクトは、django/blog です。
Git のコミット・メッセージ
前回: django_blog_2_bugfix
前々回: django_blog_1_markdown


今回やること

コメントを書けるようにして、ちょっとデータベースをいじります。(おまけ)


環境

Windows10、PyCharm、Python v3.13.2、Django v5.1.7


ディレクトリ構成

※これまでに変更・作成したファイルのみになります。

ディレクトリ構成
blog
├ media
├ static(以下、省略)
├ templates(以下、省略)
├ blog
| ├ settings.py
| └ urls.py
└ app
  ├ admin.py
  ├ context_processors.py.py
  ├ models.py
  ├ urls.py
  └ views.py

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

記事にコメントを書けるようにしていきます。
urls.py、models.py、forms.py、views.py、HTML、CSS、admin.py の順にファイルを作成していきます。

URL パスを指定します。

app/urls.py
...
urlpatterns = [
    ...
    path('comment/<int:post_pk>', views.CommentView.as_view(), name='comment'),
]

モデルを作成します。ForeignKey で Post に紐づけます。

app/models.py
...
class Comment(models.Model):
    name = models.CharField('お名前', max_length=32, default='名無し')
    comment = models.TextField('コメント', max_length=512)
    post = models.ForeignKey(Post, verbose_name='紐づく記事', on_delete=models.CASCADE)
    created_at = models.DateTimeField('作成日', auto_now_add=True)
    
    def __str__(self):
        return self.comment[:10]

フォームを作成します。表示をフォーム・クラス内と CSS ファイル(後述)で調整します。

forms.py
from django import forms
from .models import Comment

class CommentCreateForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for field in self.fields.values():
            field.widget.attrs['class'] = 'form-control'  # CSS 調整
            
    class Meta:
        model = Comment
        fields = ('name', 'comment')

ビューを作成します。コメントを書いた後は、詳細ページに遷移します。

app/views.py
from django.shortcuts import get_object_or_404, redirect
...
from .forms import CommentCreateForm
from .models import Post, Comment
...
class CommentView(generic.CreateView):
    model = Comment
    form_class = CommentCreateForm

    def form_valid(self, form):
        post_pk = self.kwargs['post_pk']
        comment = form.save(commit=False)
        comment.post = get_object_or_404(Post, pk=post_pk)
        comment.save()  # DBに保存
        return redirect('app:detail', pk=post_pk)

HTML ファイルを作成していきます。
コメント入力用のファイルを作成します。

app/comment_form.html
{% extends 'app/base.html' %}
{% block content %}
<div class="container d-flex justify-content-center"> 
  <form action="" method="POST" style="margin-top: 4rem; width: 25rem;">
    {% csrf_token %}
    {{ form }}
    <span class="d-flex justify-content-center mt-3">
      <button type="submit" class="btn  btn-dark border-light">送信</button>
    </span>
  </form>
</div>
{% endblock %}

詳細ページにコメントを表示させます。

app/post_detail.html
...
      <a class="btn m-1 bg_fc_dark" href="{% url 'app:comment' post.pk %}">コメント投稿</a>
      <a class="btn m-1 bg_fc_dark pos_right" href="{% url 'app:index' %}">ホーム</a>
      <hr>
      
      {% for comment in post.comment_set.all reversed %}
        <p class="ps-2 fs-6">
          {{ comment.name }}: ({{ comment.created_at }})<br>
          {{ comment.comment | linebreaksbr }}
        </p>
        <hr>
      {% endfor %}

    </div>
    <!-- 768ピクセル以上 -->
...

CSS ファイルで表示を調整します。

static/app/style.css
...
/* コメント入力時 */
#id_comment {
  background-color: #111;
  color: #ccc;
}
#id_name {
  background-color: #111;
  color: #ccc;
}
...

マイグレートして、動作確認します。

コマンド・プロンプト
python manage.py makemigrations
python manage.py migrate
python manage.py runserver 8080

記事を作成し、詳細画面からコメント投稿ボタンを押します。

コメントを書きます。

無事に表示されました。

管理画面で扱えるように、モデルを登録しておきます。

app/admin.py
...
from .models import Post, Category, Comment
...
admin.site.register(Comment)

管理画面でコメントを扱えるようになりました。

データベースいじり(おまけ)

今回のブログは、すべてのモデルを管理画面で操作できるようにしてるので、データベースを直接いじる必要はなさげですが、データベースに直接アクセスするのも、何かの役に立つかもなんで、少しいじってみようと思います。

データベースにアクセスします。

コマンド・プロンプト
sqlite3 db.sqlite3

コマンド一覧を表示させます。(長すぎるので画像は省略します)

sqlite
.help

すべてのテーブルを表示させます。

sqlite
.tables

スキーマ(データベースの構造)を確認します。(カラム名などを確認できます)
スペース入れて、テーブル指定すれば、個別テーブルでも確認できます。
(長すぎるので画像は省略します)

sqlite
.schema

データを取得します。(全件取得)

sqlite
select * from app_post;

条件を付けてデータを削除します。

sqlite
delete from app_post where title='てすと';

終了します。

sqlite
.exit


今回のプロジェクト(コード)

GitHub: https://github.com/Animalyzm/mikoto_project
今回のプロジェクトは、django/blog です。
Git のコミット・メッセージは、django_blog_3_comment です。
(以下、2025/7/15 に追記しました)
データベースなどは削除してるので、使用するにはマイグレートが必要になります。

コマンド・プロンプト
python manage.py makemigrations
python manage.py migrate

今回は以上になります、ありがとうございましたー♪

Discussion