Closed1
Django CBV × SuccessMessageMixin でメッセージ(ラベル指定+フェードアウト)を最小実装(Create / Delete 対応)

クラスベースビューでフェードアウトするメッセージ表示(今回はcreate + delete)を最小で実装する方法。備忘録
※本記事は Django 4.1.5 環境で検証したものです。今後のバージョンで挙動が変わる可能性があります
環境
pc:MacBook Pro(2019)
os:macos Sequoia
django: 4.1.5
できること
Django の SuccessMessageMixin を使うと、処理成功時に「◯◯を登録しました」のようなメッセージを簡単に表示できる
- CreateView
- ModelFormMixinを継承している
- フォームを介するため form.cleaned_data が存在する、そのためsuccess_message 内で
%(title)s
のようにフィールド名を埋め込み可能
- DeleteView
- ModelFormMixinを継承しないため cleaned_data が空、
%(title)s
のような置換は不可 - get_success_message() などをオーバーライドして self.object.title を参照する必要あり
- ModelFormMixinを継承しないため cleaned_data が空、
※ Django 4.1.5 の時点では DeleteView に ModelFormMixin
が含まれないためget_success_message()
のオーバーライドが必要(他バージョンで内部仕様が変わる可能性、挙動が変わる可能性あり)
サンプルコード
views.py
class CreateView(SuccessMessageMixin, generic.CreateView):
model = [model名]
form_class = [フォーム名]
success_url = reverse_lazy('app名:index')
# 内部的にcleaned_data`が渡されるため%(title)s = cleaned_data["title"]と同義
success_message = "%(title)s をアップロードしました"
・
・
class DeleteView(SuccessMessageMixin, generic.DeleteView):
model = [model名]
success_url = reverse_lazy('app名:index')
success_message = "%(title)s"
def get_success_message(self, cleaned_data):
return f"{self.object.title} を削除しました。"
・
・
forms.py
from django import forms
from .models import [model名]
class MovieCreateForm(forms.ModelForm):
class Meta:
model = [model名]
fields = ('title', 'description', 'thumbnail', 'upload')
# bootstrapのクラスをカスタマイズするため定義
# 今回は[title]を使いメッセージ表示
widgets = {
'title': forms.TextInput(attrs={ # <input type="text" class="form-control"
'class': 'form-control',
}),
'description': forms.Textarea(attrs={ # <textarea class="form-cotrol"
'class': 'form-control',
}),
'thumbnail': forms.ClearableFileInput(attrs={ # <input type="file" class="form-control-file"
'class': "form-control-file",
}),
'upload': forms.ClearableFileInput(attrs={
'class': "form-control-file",
}),
}
メッセージを表示させたいテンプレートファイル
{% if messages %}
{% for message in messages %}
<div class="alert alert-success text-center fade show" role="alert">{{ message }}</div>
{% endfor %}
{% endif %}
・
・
<script>
setTimeout(function () {
document.querySelectorAll('.alert').forEach(function (el) {
el.classList.remove('show');
});
}, 10000);
</script>
イメージ
継承内容確認
- CreateView に
ModelFormMixin
が入っていることを確認できる - DeleteView には
FormMixin
は入っているがModelFormMixin
は無いため、cleaned_data
は使えない
$ python manage.py shell
$ from django.views import generic
$ print(generic.CreateView.__mro__)
(<class 'django.views.generic.edit.CreateView'>, <class 'django.views.generic.detail.SingleObjectTemplateResponseMixin'>
, <class 'django.views.generic.base.TemplateResponseMixin'>, <class 'django.views.generic.edit.BaseCreateView'>, <
class 'django.views.generic.edit.ModelFormMixin'>, <class 'django.views.generic.edit.FormMixin'>, <class '
django.views.generic.detail.SingleObjectMixin'>, <class 'django.views.generic.base.ContextMixin'>, <class '
django.views.generic.edit.ProcessFormView'>, <class 'django.views.generic.base.View'>, <class 'object'>)
$ print(generic.DeleteView.__mro__)
(<class 'django.views.generic.edit.DeleteView'>, <class 'django.views.generic.detail.SingleObjectTemplateResponseMixin'>
, <class 'django.views.generic.base.TemplateResponseMixin'>, <class 'django.views.generic.edit.BaseDeleteView'>, <
class 'django.views.generic.edit.DeletionMixin'>, <class 'django.views.generic.edit.FormMixin'>, <class '
django.views.generic.detail.BaseDetailView'>, <class 'django.views.generic.detail.SingleObjectMixin'>, <class '
django.views.generic.base.ContextMixin'>, <class 'django.views.generic.base.View'>, <class 'object'>)
SuccessMessageMixinの流れ
- SuccessMessageMixin は form_valid() をオーバーライドしている
SuccessMessageMixin
from django.contrib import messages
class SuccessMessageMixin:
"""
Add a success message on successful form submission.
"""
success_message = ""
def form_valid(self, form):
response = super().form_valid(form)
success_message = self.get_success_message(form.cleaned_data)
if success_message:
messages.success(self.request, success_message)
return response
def get_success_message(self, cleaned_data):
return self.success_message % cleaned_data
CreateView の場合
- CreateView は ModelFormMixin を継承している。
- form_valid(form) が呼ばれる処理経路に乗るので、SuccessMessageMixin.form_valid() も実行される。
- form.cleaned_data が渡されて get_success_message(cleaned_data) が呼ばれる。
- %(title)s のような置換が効く。
DeleteView の場合
- DeleteView は ModelFormMixin を持たない。
- 削除処理は post() → delete() という別ルートで進む。
- form_valid() が呼ばれない。
- 結果的に SuccessMessageMixin.form_valid() も呼ばれない。
- get_success_message() は自動で発火しない。なのでオーバーライドが必要
このスクラップは3日前にクローズされました