Python Django 入門トップページ


ユーザ認証とコメント掲示板の開発

  1. プロジェクトの概要
  2. プロジェクトの作成と初期設定
  3. アプリケーションの作成と有効化
  4. ルートの記述
  5. ビューの定義
  6. HTML のテンプレート化
  7. HTML ファイルの作成
  8. Web ページ雛形の表示確認
  9. トップページの作成
  10. データベースのマイグレーション
  11. ユーザの作成
  12. ユーザ認証機能の実装
  13. セッション情報の確認
  14. ユーザ認証の状態を表示
  15. Navbar を設置
  16. モデルの作成とマイグレーション
  17. テストデータの投入
  18. コメントの一覧表示
  19. ページネーションと更新逆順表示
  20. コメント投稿機能の実装
  21. フラッシュメッセージ
  22. コメント詳細表示ページの実装
  23. 投稿者のユーザ名とメールアドレスの表示
  24. 投稿者であるかどうかの判断
  25. 編集・更新機能の実装
  26. コメント削除機能の実装
  27. Navbar の調整
  28. Profile の表示
  29. Profile の編集と更新
  30. パスワードの変更
  31. 管理サイトの準備
  32. 管理ユーザの登録
  33. 管理サイトへのログインとスタッフの登録
  34. グループの追加と権限の付与
  35. 管理サイトに comments アプリケーションを登録
  36. Comments アプリケーションから管理サイトへ

ユーザ認証とコメント掲示板の開発

コメント投稿機能の実装

次に投稿機能を実装しよう.まず,forms.py にフォームの要素を定義します.それと同時にホワイトスペースの削除と入力内容を検証するための関数も定義します.

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

class CommentForm(forms.ModelForm):

    class Meta:
        model = Comment
        fields = ('title', 'body')
        widgets = {
              'title': forms.TextInput(attrs={
              'class': 'form-control'
            }),
              'body': forms.TextInput(attrs={
              'class': 'form-control'
            }),
        }
        labels = {
            'title': 'タイトル',
            'body': '本文',
        }

    def clean(self):
        data = super().clean()
        title = data.get('title')
        body = data.get('body')
        if title is None:
            msg = "タイトルが入力されていません"
            self.add_error('title', msg)
        elif len(title) > 10:
            msg = "タイトルの最大文字数は10文字です"
            self.add_error('title', msg)
        if body is None:
            msg = "本文が入力されていません"
            self.add_error('body', msg)
        elif len(body) > 20:
            msg = "本文の最大文字数は20文字です"
            self.add_error('body', msg)

次に,form.html の中に,フォームの要素を配置し forms.py を読み込みます.

comments/templates/comments/form.html
{% extends "base.html" %}

{% block title %}
{{ page_title }}
{% endblock %}

{% block content %}
<h1 class="my-5">{{ form_name }}</h1>
<form method="POST">
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit" class="btn btn-primary">{{ button_label }}</button>
</form>
<ul>
    <li>
        <a href="{% url 'comments:index' %}">コメント一覧</a>
    </li>
    <li>
        <a href="{% url 'comments:show' 10  %}">コメント詳細</a>
    </li>
    <li>
        <a href="{% url 'comments:create' %}">コメント投稿</a>
    </li>
    <li>
        <a href="{% url 'comments:update' 10  %}">コメント更新</a>
    </li>
    <li>
        <a href="{% url 'comments:delete' 10  %}">コメント削除</a>
    </li>
    <li>
        <a href="/">トップページへ</a>
    </li>
</ul>
{% endblock content %}

views.py には投稿の処理を定義します.

comments/views.py
from django.conf import settings
from django.shortcuts import render
from django.contrib.auth import authenticate, login, logout
from django.shortcuts import redirect
from django.urls import reverse
from .models import Comment
from .forms import CommentForm
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger

# Create your views here.

...(中略)...

def comments_create(request):
    if not request.user.is_authenticated:
        return redirect('%s?next=%s' % (settings.LOGIN_URL, request.path))
    # context = {}
    # context['page_title'] = 'コメントの投稿'
    # return render(request, 'comments/form.html', context)
    if request.method == 'POST':
        form = CommentForm(request.POST)
        if form.is_valid():
            comment = Comment()
            comment.title = form.cleaned_data.get("title")
            comment.body = form.cleaned_data.get("body")
            comment.owner_id = request.user.id
            comment.save()
            return redirect(reverse('comments:index'))
        else:
            # エラーメッセージをつけて返す
            context = {}
            context['page_title'] = 'コメントの投稿'
            context['form_name'] = 'コメントの投稿'
            context['button_label'] = 'コメントを投稿する'
            context['form'] = form
            return render(request, 'comments/form.html', context)
    else:
        context = {}
        context['form'] = CommentForm(
                            initial={
                                # 'title' : 'title',
                            }
                        )
        context['page_title'] = 'コメントの投稿'
        context['form_name'] = 'コメントの投稿'
        context['button_label'] = 'コメントを投稿する'
        return render(request, 'comments/form.html', context)

Web サーバを起動し,user_a でログインした状態でコメントを投稿してみる.

(py39) C:\Users\lecture\Documents\django\django_comment_auth>python manage.py runserver ⏎
Watching for file changes with StatReloader
Performing system checks...

コメントの投稿ページを開こうとしたときには GET メソッドが Web サーバにリクエストされることになるので,views.py の 38〜47 行目の処理が実行されます.

django2022-00095

上の画面で「コメントを投稿する」ボタンをクリックすると,今度は POST メソッドで Web サーバにリクエストされることになるので,views.py の 21〜36 行目の処理が実行されることになります.投稿できれば次の画面にリダイレクトされます.

django2022-00096

投稿されたコメントには投稿者の user_id が owner_id として保存されていること確認しよう.

(py39) C:\Users\lecture\Documents\django\django_comment_auth>sqlite3 db.sqlite3 ⏎
SQLite version 3.38.2 2022-03-26 13:51:10
Enter ".help" for usage hints.
sqlite> .headers ON ⏎
sqlite> select * from comments_comment; ⏎
id|title|body|created_at|updated_at|owner_id
1|最初のコメント (a)|コメントの本文|2022-07-27 11:01:00|2022-07-27 11:01:00|1
2|2個目のコメント (b)|コメントの本文2|2022-07-27 11:02:00|2022-07-27 11:02:00|2
3|<3個目>のコメント (a)|<h1>コメントの本文3</h1>|2022-07-27 11:03:00|2022-07-27 11:03:00|1
4|4個目のコメント (b)|コメントの本文4|2022-07-27 11:04:00|2022-07-27 11:04:00|2
5|5個目のコメント (a)|コメントの本文5|2022-07-27 11:05:00|2022-07-27 11:05:00|1
6|6個目のコメント (b)|コメントの本文6|2022-07-27 11:06:00|2022-07-27 11:06:00|2
7|7個目のコメント (a)|コメントの本文7|2022-07-27 11:07:00|2022-07-27 11:07:00|1
8|8個目のコメント (b)|コメントの本文8|2022-07-27 11:08:00|2022-07-27 11:08:00|2
9|9個目のコメント (a)|コメントの本文9|2022-07-27 11:09:00|2022-07-27 11:20:00|1
10|10個目のコメント (b)|コメントの本文10|2022-07-27 11:10:00|2022-07-27 11:10:00|2
11|user_a|User Aが投稿します|2022-07-27 19:15:38.402622|2022-07-27 19:15:38.402622|1
sqlite> .exit ⏎

(py39) C:\Users\lecture\Documents\django\django_comment_auth>

次は投稿完了時にフラッシュメッセージが表示されるようにしよう.

目次に戻る