【Django】メッセージ機能の実装／【Bootstrap】トーストの実装

# 【Bootstrap】トーストの実装とメッセージ機能
サインアップに成功したら、右上に半透明でメッセージを表示したい。

イメージ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3784177/d387e184-3933-4fe3-a63a-30165eae6243.png)


# メッセージ機能の実装

「アカウントが作成されました！」とメッセージを表示させる。djangoの標準機能である、mixinを使うのが最も簡単な方法。

https://docs.djangoproject.com/ja/5.1/ref/contrib/messages/

```diff_python:  views.py
...
+ from django.contrib.messages.views import SuccessMessageMixin


- class SignupView(CreateView):
+ class SignupView(SuccessMessageMixin, CreateView):
    """ ユーザー登録用ビュー """
    form_class = SignUpForm
    template_name = "signup.html" 
    success_url = reverse_lazy("list") # ユーザー作成後のリダイレクト先ページ
+   success_message = "アカウントが作成されました！"

```

- class SignupView(SuccessMessageMixin, CreateView):　では、左に書いたSuccessMessageMixinが優先して継承される

---

まずはシンプルな形でテンプレートに追加。サインアップを試し、メッセージが表示されるか動作確認する。

```diff_html: html（トーストを表示するページ）
<!-- メッセージを表示（トースト） -->
<div class="container">
  {% if messages %}
  {% for message in messages %}
        <div class="text-center alert alert-success">
        {{ message }}
      </div>
  {% endfor %}
  {% endif %} 
</div>
```


# トーストの実装

**1: `html` にメッセージの追加**

何かメッセージを受け取ったら、トーストに表示するように書いています。

```diff_html: html（トーストを表示するページ）
<!-- メッセージを表示（トースト） -->
- <div class="container">
+ <div class="toast-container position-fixed top-0 end-0 p-3">
  {% if messages %}
  {% for message in messages %}
-  <div class="text-center alert alert-success">
+  <div class="toast" role="alert" aria-live="assertive" aria-atomic="true" data-bs-autohide="true">
+      <div class="toast-header">
+          <strong class="me-auto">通知</strong>
+          <button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
+      </div>
+      <div class="toast-body">
          {{ message }}
+      </div>
  </div>
  {% endfor %}
  {% endif %} 
</div>

```

- `messages` に格納されたメッセージをトーストとして表示
- `.toast-container` を `position-fixed` にして、画面の右上に表示
- `data-bs-autohide="true"` により一定時間後に自動的に消える

:::note info
`<div class="alert alert-success">` は無くていい？
→ `alert alert-success` は、トーストには不要
:::

**アラートとトースト のちがい**


**アラート (`alert alert-success`)**  
- ページ内に**固定表示**される通知（ユーザーが閉じるまで残る）
- `class="alert alert-success"` を使うことで、成功メッセージとして表示

**トースト (`toast`)** 
- **画面の隅にポップアップ表示**される通知
- `bootstrap.Toast` を使うことで、**一定時間後に自動で消えるようにすることが可能**
- `alert` ではなく `toast` を使うことで、より軽量な通知を作成

---
**2: `base.html` の最後にJavaScript追加**

Bootstrapのトーストを動かすために、`base.html` の最後に以下のスクリプトを追加します。`base.html` に追加すると、どのページでも使えるようになります。

JavaScriptの追加位置は、\<body>タグの最後が一般的。

```diff_html: base.html
...
    <!-- BootstrapトーストのJS -->
    <script>
        document.addEventListener("DOMContentLoaded", function () {
            var toastEls = document.querySelectorAll(".toast");
            toastEls.forEach(function (toastEl) {
                var toast = new bootstrap.Toast(toastEl);
                toast.show();
            });
        });
   </script>

   <!-- BootstrapのJS -->
   <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
  </body>
</html>
```

これは **ページが読み込まれたときに Bootstrap のトーストをすべて表示する** ためのものです。

- `addEventListener` → イベント（クリック・キー入力など）が発生したときに動作する処理を追加するためのJavaScriptのメソッド
- `DOMContentLoaded` → **HTMLの読み込みが終わったら、処理を実行する**
- `querySelectorAll(".toast")` → **HTMLにある全てのトースト要素を取得**  
- `.forEach()` → **トーストを1つずつ処理**  
- `new bootstrap.Toast(toastEl)` → **トースト機能を有効化**  
- `toast.show()` → **トーストを表示**
- `var` は変数の定義


:::note info
（初心者）squeryって何？
「query（クエリ）」は、情報を検索・取得するための**問い合わせやリクエスト**のことを指します。
JavaScript では、`querySelector()` という関数を使って、**HTML要素を取得** できます。
:::

# 参考

以下の記事を参考にさせていただきました。

https://getbootstrap.jp/docs/5.3/components/toasts/#%E6%A6%82%E8%A6%81

https://takabus.com/tips/721/

https://stackoverflow.com/questions/63515279/how-to-initialize-toasts-with-javascript-in-bootstrap-5