【Django】フラッシュメッセージを実装する|簡単な掲示板アプリの作成

Djangoの標準機能「messagesフレームワーク」を用いて、ユーザーの操作結果を知らせるフラッシュメッセージの実装方法を解説します。投稿成功やログイン失敗などの通知を画面に表示し、jQueryを使って数秒後に自動でフェードアウトさせる方法まで、初心者にも分かりやすく学べます。

作成日: 更新日:

開発環境

  • OS: Windows10
  • Visual Studio Code: 1.73.0
  • Python: 3.10.11
  • Django: 5.0.3

サンプルコード

/app/views.py

/app/views.py
1 from django.conf import settings
2 from django.template.loader import render_to_string
3 from django.core.paginator import Paginator
4+from django.contrib import messages
5 
6 def user_owns_board(view_func):
7     @wraps(view_func)
8         if form.is_valid():
9             form.instance.user = request.user
10             form.save()
11+            messages.success(request, '投稿が成功しました!')
12             return redirect('index')
13+        else:
14+            messages.error(request, '入力内容にエラーがあります。')
15     else:
16         form = BoardForm()
17     return render(request, 'new.html', {'form': form})
18 class CustomLoginView(LoginView):
19     template_name = 'registration/login.html'
20 
21+    def form_valid(self, form):
22+        # ログインに成功した場合の処理
23+        messages.success(self.request, 'ログインに成功しました。')
24+        return super().form_valid(form)
25+
26+    def form_invalid(self, form):
27+        # ログインに失敗した場合の処理
28+        messages.error(self.request, 'ログインに失敗しました。ユーザー名とパスワードを確認してください。')
29+        return super().form_invalid(form)
30+
31 # ログアウト
32 def logout_view(request):
33     logout(request)
34+    messages.success(request, 'ログアウトに成功しました。')
35     return redirect('index')
36 
37 # サインアップページのビュー
38         form = SignUpForm(request.POST)
39         if form.is_valid():
40             form.save()
41+            messages.success(request, 'サインアップに成功しました。')
42             return redirect('login')
43+        else:
44+            messages.error(request, '入力内容にエラーがあります。')
45     else:
46         form = SignUpForm()
47     return render(request, 'registration/signup.html', {'form': form})
48

/config/settings.py

/config/settings.py
1     "django.middleware.clickjacking.XFrameOptionsMiddleware",
2 ]
3 
4+MESSAGE_STORAGE = 'django.contrib.messages.storage.session.SessionStorage'
5+
6 ROOT_URLCONF = "config.urls"
7 
8 TEMPLATES = [
9

/config/urls.py

/config/urls.py
1 from django.urls import path, include
2 from django.contrib.auth import views as auth_views
3 from app import views
4+from app.views import CustomLoginView
5 
6 urlpatterns = [
7     path("admin/", admin.site.urls),
8     path('', include('app.urls')),
9-    path('accounts/login/', auth_views.LoginView.as_view(), name='login'),
10+    path('accounts/login/', CustomLoginView.as_view(), name='login'),
11     path('accounts/logout/', views.logout_view, name='logout'),
12     path('accounts/signup/', views.signup, name='signup'),
13     path('accounts/profile/', views.profile, name='profile'),
14

/static/js/common.js

/static/js/common.js
1+// ページロード時にフラッシュメッセージをフェードアウトする
2+$(document).ready(function(){
3+    $(".alert").delay(3000).fadeOut("slow");
4+});
5

/templates/base.html

/templates/base.html
1     <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css">
2     <!-- CSSファイルを読み込む -->
3     <link rel="stylesheet" type="text/css" href="{% static 'css/styles.css' %}">
4+    <!-- jQueryのCDNを読み込む -->
5+    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
6+    <!-- BootstrapのCDNを読み込む -->
7+    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
8+    <!-- 静的ファイルとして保存されたJavaScriptを読み込む -->
9+    <script src="{% static 'js/common.js' %}"></script>
10 </head>
11 <body>
12     <!-- ヘッダーの内容 -->
13         </div>
14     </header>
15 
16+    <!-- フラッシュメッセージ -->
17+    {% if messages %}
18+        <div class="text-center">
19+            {% for message in messages %}
20+                {% if message.tags == 'success' %}
21+                    <div class="alert alert-success alert-dismissible fade show" role="alert">
22+                        {{ message }}
23+                        <button type="button" class="btn-close" data-dismiss="alert" aria-label="Close"></button>
24+                    </div>
25+                {% elif message.tags == 'error' %}
26+                    <div class="alert alert-danger alert-dismissible fade show" role="alert">
27+                        {{ message }}
28+                        <button type="button" class="btn-close" data-dismiss="alert" aria-label="Close"></button>
29+                    </div>
30+                {% endif %}
31+            {% endfor %}
32+        </div>
33+    {% endif %}
34+
35     <!-- 各ページの内容 -->
36     <main>
37         <div class="container">
38

コード解説

変更点: メッセージを保存する方法の設定

/config/settings.py
1     "django.middleware.clickjacking.XFrameOptionsMiddleware",
2 ]
3 
4+MESSAGE_STORAGE = 'django.contrib.messages.storage.session.SessionStorage'
5+
6 ROOT_URLCONF = "config.urls"
7 
8 TEMPLATES = [

settings.pyファイルに MESSAGE_STORAGE という設定を追加しています。これは、Djangoのmessagesフレームワークが生成したメッセージをどこに保存するかを指定するためのものです。'django.contrib.messages.storage.session.SessionStorage' を指定することで、メッセージがユーザーのセッション情報の中に一時的に保存されます。これにより、リクエストをまたいで、例えば投稿処理後のリダイレクト先ページで「投稿が成功しました!」といったメッセージを表示できるようになります。

変更点: ビューでmessagesフレームワークをインポート

/app/views.py
1 from django.conf import settings
2 from django.template.loader import render_to_string
3 from django.core.paginator import Paginator
4+from django.contrib import messages

views.pyファイルで、from django.contrib import messages という行を追加しました。これは、Djangoに標準で備わっているmessagesフレームワークの機能(例: messages.success())をビューの中で使えるようにするために必要なインポート文です。

変更点: 掲示板への投稿処理にメッセージを追加

/app/views.py
1         if form.is_valid():
2             form.instance.user = request.user
3             form.save()
4+            messages.success(request, '投稿が成功しました!')
5             return redirect('index')
6+        else:
7+            messages.error(request, '入力内容にエラーがあります。')

新規投稿を行うビュー new_board の処理を修正しています。 フォームへの入力が正しく、投稿が成功した場合には messages.success(request, '投稿が成功しました!') を実行します。これは、「成功」レベルのメッセージを登録する命令です。 一方、フォームの入力に誤りがあった場合には messages.error(request, '入力内容にエラーがあります。') を実行し、「エラー」レベルのメッセージを登録しています。 request を第一引数に渡すことで、どのユーザーのリクエストに対するメッセージかをDjangoが判断できるようになります。

変更点: ログイン処理にメッセージを追加

/app/views.py
1 class CustomLoginView(LoginView):
2     template_name = 'registration/login.html'
3 
4+    def form_valid(self, form):
5+        # ログインに成功した場合の処理
6+        messages.success(self.request, 'ログインに成功しました。')
7+        return super().form_valid(form)
8+
9+    def form_invalid(self, form):
10+        # ログインに失敗した場合の処理
11+        messages.error(self.request, 'ログインに失敗しました。ユーザー名とパスワードを確認してください。')
12+        return super().form_invalid(form)

Djangoの標準ログインビュー LoginView を継承した CustomLoginView を作成し、処理をカスタマイズしています。 form_valid メソッドはログインが成功したときに呼び出されます。ここで messages.success() を使い、成功メッセージを登録しています。 form_invalid メソッドはログインが失敗したときに呼び出されます。ここでは messages.error() を使い、失敗メッセージを登録しています。 super().form_valid(form) は、親クラス(元のLoginView)の本来の処理を呼び出すための記述です。

変更点: ログアウト処理にメッセージを追加

/app/views.py
1 # ログアウト
2 def logout_view(request):
3     logout(request)
4+    messages.success(request, 'ログアウトに成功しました。')
5     return redirect('index')

ユーザーがログアウトする際のビュー logout_view に、messages.success(request, 'ログアウトに成功しました。') という行を追加しました。これにより、ログアウトが正常に完了したことをユーザーに知らせるメッセージが表示されるようになります。

変更点: サインアップ(ユーザー登録)処理にメッセージを追加

/app/views.py
1         form = SignUpForm(request.POST)
2         if form.is_valid():
3             form.save()
4+            messages.success(request, 'サインアップに成功しました。')
5             return redirect('login')
6+        else:
7+            messages.error(request, '入力内容にエラーがあります。')

サインアップ(新規ユーザー登録)のビューにメッセージ機能を追加しました。 フォームの入力内容が正しく、ユーザー登録が成功した場合は messages.success() で成功メッセージを登録します。 入力内容にエラーがあった場合は messages.error() でエラーメッセージを登録し、ユーザーに問題を知らせます。

変更点: カスタマイズしたログインビューを使うようにURLを変更

/config/urls.py
1 from django.urls import path, include
2 from django.contrib.auth import views as auth_views
3 from app import views
4+from app.views import CustomLoginView
5 
6 urlpatterns = [
7     path("admin/", admin.site.urls),
8     path('', include('app.urls')),
9-    path('accounts/login/', auth_views.LoginView.as_view(), name='login'),
10+    path('accounts/login/', CustomLoginView.as_view(), name='login'),
11     path('accounts/logout/', views.logout_view, name='logout'),
12     path('accounts/signup/', views.signup, name='signup'),

urls.py を編集し、ログインページのURL (/accounts/login/) が呼び出された際に、Django標準の LoginView ではなく、先ほどメッセージ機能を追加した CustomLoginView を使うように設定を変更しています。これにより、ログイン成功・失敗時にメッセージが表示されるようになります。

変更点: JavaScriptライブラリと自作JSファイルの読み込み

/templates/base.html
1     <link rel="stylesheet" type="text/css" href="{% static 'css/styles.css' %}">
2+    <!-- jQueryのCDNを読み込む -->
3+    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
4+    <!-- BootstrapのCDNを読み込む -->
5+    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
6+    <!-- 静的ファイルとして保存されたJavaScriptを読み込む -->
7+    <script src="{% static 'js/common.js' %}"></script>
8 </head>

すべてのページの基礎となる base.html に、JavaScriptを動作させるためのコードを追加しました。

  1. jQuery: JavaScriptをより簡単に書くためのライブラリです。CDNという形式でインターネット上から直接読み込んでいます。
  2. Bootstrap: Webサイトのデザインを整えるBootstrapのJavaScript部分です。メッセージを閉じるボタンなどの機能に必要です。
  3. common.js: 私たちが作成したJavaScriptファイルです。{% static 'js/common.js' %} という書き方で、Djangoが管理する静的ファイル(static)の中からこのファイルを読み込んでいます。

変更点: フラッシュメッセージを表示するためのHTMLを追加

/templates/base.html
1     </header>
2 
3+    <!-- フラッシュメッセージ -->
4+    {% if messages %}
5+        <div class="text-center">
6+            {% for message in messages %}
7+                {% if message.tags == 'success' %}
8+                    <div class="alert alert-success alert-dismissible fade show" role="alert">
9+                        {{ message }}
10+                        <button type="button" class="btn-close" data-dismiss="alert" aria-label="Close"></button>
11+                    </div>
12+                {% elif message.tags == 'error' %}
13+                    <div class="alert alert-danger alert-dismissible fade show" role="alert">
14+                        {{ message }}
15+                        <button type="button" class="btn-close" data-dismiss="alert" aria-label="Close"></button>
16+                    </div>
17+                {% endif %}
18+            {% endfor %}
19+        </div>
20+    {% endif %}
21+
22     <!-- 各ページの内容 -->
23     <main>

base.html に、ビューで登録されたフラッシュメッセージを実際に画面に表示するためのHTMLコードを追加しました。

  • {% if messages %}: Djangoのテンプレートタグです。表示すべきメッセージが存在する場合にのみ、内側のコードを実行します。
  • {% for message in messages %}: 登録されているメッセージを1つずつ取り出して処理を繰り返します。
  • {{ message }}: ビューで設定したメッセージの文字列(例: '投稿が成功しました!')がここに表示されます。
  • {% if message.tags == 'success' %}: メッセージのレベル(successerrorなど)を判定しています。これにより、成功メッセージは緑色 (alert-success)、エラーメッセージは赤色 (alert-danger) のように、BootstrapのCSSクラスを使って見た目を変えることができます。

変更点: メッセージを自動で消すJavaScriptコードの追加

/static/js/common.js
1+// ページロード時にフラッシュメッセージをフェードアウトする
2+$(document).ready(function(){
3+    $(".alert").delay(3000).fadeOut("slow");
4+});

新しく作成した common.js ファイルに、jQueryを使ったコードを記述しました。

  • $(document).ready(function(){ ... });: ページのHTMLがすべて読み込まれた後に、中の処理を実行するという意味です。
  • $(".alert"): alertというCSSクラスが指定されたHTML要素(今回の場合、フラッシュメッセージ全体)を選択します。
  • .delay(3000): 3000ミリ秒、つまり3秒間、次の処理を待機させます。
  • .fadeOut("slow"): 選択した要素をゆっくりとフェードアウト(だんだん薄くして消す)させます。 このコードにより、表示されたフラッシュメッセージが3秒後に自動的に消えるようになります。

おわりに

今回はDjangoのmessagesフレームワークを使い、フラッシュメッセージの実装方法を学びました。views.pyにて投稿やログインといった処理の結果に応じ、messages.success()messages.error()を呼び出すだけで簡単にメッセージを登録できることを確認しました。base.htmlでこれらのメッセージを表示し、さらにjQueryで数秒後に自動で消えるアニメーションを加えることで、ユーザーに分かりやすいフィードバックを提供できるようになります。この一連の実装は、ユーザーにとって使いやすいWebアプリケーションを開発するための重要な機能です。

関連コンテンツ