Python | Django | class-based viewsにおけるSuccessMessageMixinの使い方

公開日:2021/8/23

Pythonには,DjangoというWebアプリケーションフレームワークがある.フレームワークのため,Djangoを利用するとWebアプリを通常よりも短時間で開発することが可能になる.

class-based viewsは,viewsを実装する手段の1つであり,関数の代わりにPythonのオブジェクトとしてviewsを定義する.viewsの作成とデータの追加・更新・削除が容易になる.

前記事では,「class-based viewsのRedirectViewの使い方」を作成した.前記事での設定をそのまま引き継いだ上で,本記事では,「class-based viewsにおけるSuccessMessageMixinの使い方」を以下3つの構成にて記す.

  1. 基本の利用
  2. “get_success_message"を利用
  3. 参照

◆実施環境

Python 3.8.8
Django 3.2.3
VS Code 1.59.0

■class-based viewsにおけるSuccessMessageMixinの使い方

データ更新や削除などのアクション時にメッセージを表示する際,SuccessMessageMixinが利用される.

  1. 基本の利用

“ec_site/views.py"に追記し,以下のように編集する.

from django.shortcuts import render
from django.views.generic.base import (
    View, TemplateView, RedirectView,
)
from django.views.generic.detail import DetailView
from django.views.generic.list import ListView
from django.views.generic.edit import (
    CreateView, UpdateView, DeleteView,
    FormView,
)
from . import forms
import random
from .models import Medicines
from datetime import datetime
from django.urls import reverse_lazy
from django.contrib.messages.views import SuccessMessageMixin # 追記箇所

class TopView(View):

    def get(self, request, *args, **kwargs):
        medicine_form = forms.MedicineForm()
        return render(request, 'top.html', context={
            'medicine_form': medicine_form,
        })

    def post(self, request, *args, **kwargs):
        medicine_form = forms.MedicineForm(request.POST or None)
        if medicine_form.is_valid():
            medicine_form.save()
        return render(request, 'top.html', context={
            'medicine_form': medicine_form,
        })

class HomeView(TemplateView):

    template_name = 'home.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['name'] = kwargs.get('name')
        context['alphabet'] = random.randint(0,9999)
        return context

class MedicineDetailView(DetailView):
    model = Medicines
    template_name = 'medicine.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['time'] = datetime.now()
        return context

class MedicineListView(ListView):
    model = Medicines
    template_name = 'medicine_list.html'

    def get_queryset(self):
        qs = super(MedicineListView, self).get_queryset()
        if 'name' in self.kwargs:
            qs = qs.filter(name__startswith=self.kwargs['name'])
        qs = qs.order_by('-id')
        return qs

class MedicineCreateView(CreateView):
    model = Medicines
    fields = ['name', 'description', 'price']
    template_name = 'insert_medicine.html'

    def form_valid(self, form):
        form.instance.create_time = datetime.now()
        form.instance.update_time = datetime.now()
        return super(MedicineCreateView, self).form_valid(form)

    def get_initial(self, **kwargs):
        initial = super(MedicineCreateView, self).get_initial(**kwargs)
        initial['price'] = '1000'
        return initial

class MedicineUpdateView(SuccessMessageMixin, UpdateView): # 変更箇所
    template_name = 'update_medicine.html'
    model = Medicines
    form_class = forms.MedicineUpdateForm
    success_message = 'Update is successful!' # 追記箇所(83~86行目)

    def get_success_url(self):
        return reverse_lazy('ec_site:update_medicine', kwargs={'pk': self.object.id})

class MedicineDeleteView(DeleteView):
    model = Medicines
    template_name = 'delete_medicine.html'
    success_url = reverse_lazy('ec_site:list_medicines')

class MedicineFormView(FormView):

    template_name = 'form_medicine.html'
    form_class = forms.MedicineForm
    success_url = reverse_lazy('ec_site:list_medicines')

    def get_initial(self):
        initial = super(MedicineFormView, self).get_initial()
        initial['price'] = '2000'
        return initial

    def form_valid(self, form):
        if form.is_valid():
            form.save()
        return super(MedicineFormView, self).form_valid(form)

class MedicineRedirectView(RedirectView):
    url = 'https://shelokuma.com'

    def get_redirect_url(self, *args, **kwargs):
        medicine = Medicines.objects.last()
        if 'pk' in kwargs:
            return reverse_lazy('ec_site:detail_medicine', kwargs={'pk':kwargs['pk']})
        
        return reverse_lazy('ec_site:update_medicine', kwargs={'pk': medicine.pk})

“templates/update_medicine.html"に追記し,以下のように編集する.

{% if messages %} # 追記箇所(1~5行目)
{% for message in messages %}
  {{ message.message }}
{% endfor %}
{% endif %}
<form method="POST">
  {% csrf_token %}
  {{ form.as_p }}
  <input type="submit" value="update">
</form>

VS Codeの"View"を開き,"Terminal"をクリックする.クリックするとVS Codeの下部にターミナルが開くので,”conda activate 仮想環境名”を実行し,仮想環境に移行する(移行方法の詳細はこちら).その後,ターミナルで"cd class_based_view"(プロジェクト名)を入力し,ディレクトリを変更する.変更後,以下のように”python manage.py runserver”を実行する.以下が出力される.

(djangoenv) C:\Users\shiro\Desktop\210517_python development\myclassbasedviewtest\class_based_view
>python manage.py runserver
Watching for file changes with StatReloader
Performing system checks...

System check identified no issues (0 silenced). # 以下出力箇所
August 23, 2021 - 01:10:21
Django version 3.2.3, using settings 'class_based_view.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.

上記の"http://127.0.0.1:8000/"をクリックすると,ブラウザが開き,以下画面が出力される.

ブラウザのURLに"http://127.0.0.1:8000/ec_site/update_medicine/4″と入力すると,以下更新ページに遷移する.赤枠の内容(Description, Price)を変更する.

以下赤枠のようにDescriptionとPriceを変更し,"update"をクリックすると,上段の赤枠のメッセージが出力された.

  1. “get_success_message"の利用

“ec_site/views.py"に追記し,以下のように更新する.

from django.shortcuts import render
from django.views.generic.base import (
    View, TemplateView, RedirectView,
)
from django.views.generic.detail import DetailView
from django.views.generic.list import ListView
from django.views.generic.edit import (
    CreateView, UpdateView, DeleteView,
    FormView,
)
from . import forms
import random
from .models import Medicines
from datetime import datetime
from django.urls import reverse_lazy
from django.contrib.messages.views import SuccessMessageMixin

class TopView(View):

    def get(self, request, *args, **kwargs):
        medicine_form = forms.MedicineForm()
        return render(request, 'top.html', context={
            'medicine_form': medicine_form,
        })

    def post(self, request, *args, **kwargs):
        medicine_form = forms.MedicineForm(request.POST or None)
        if medicine_form.is_valid():
            medicine_form.save()
        return render(request, 'top.html', context={
            'medicine_form': medicine_form,
        })

class HomeView(TemplateView):

    template_name = 'home.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['name'] = kwargs.get('name')
        context['alphabet'] = random.randint(0,9999)
        return context

class MedicineDetailView(DetailView):
    model = Medicines
    template_name = 'medicine.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['time'] = datetime.now()
        return context

class MedicineListView(ListView):
    model = Medicines
    template_name = 'medicine_list.html'

    def get_queryset(self):
        qs = super(MedicineListView, self).get_queryset()
        if 'name' in self.kwargs:
            qs = qs.filter(name__startswith=self.kwargs['name'])
        qs = qs.order_by('-id')
        return qs

class MedicineCreateView(CreateView):
    model = Medicines
    fields = ['name', 'description', 'price']
    template_name = 'insert_medicine.html'

    def form_valid(self, form):
        form.instance.create_time = datetime.now()
        form.instance.update_time = datetime.now()
        return super(MedicineCreateView, self).form_valid(form)

    def get_initial(self, **kwargs):
        initial = super(MedicineCreateView, self).get_initial(**kwargs)
        initial['price'] = '1000'
        return initial

class MedicineUpdateView(SuccessMessageMixin, UpdateView):
    template_name = 'update_medicine.html'
    model = Medicines
    form_class = forms.MedicineUpdateForm
    success_message = 'Update is successful!'

    def get_success_url(self):
        return reverse_lazy('ec_site:update_medicine', kwargs={'pk': self.object.id})

    def get_success_message(self, cleaned_data): # 追記箇所(88~89行目)
        return cleaned_data.get('name') + ' was updated'

class MedicineDeleteView(DeleteView):
    model = Medicines
    template_name = 'delete_medicine.html'
    success_url = reverse_lazy('ec_site:list_medicines')

class MedicineFormView(FormView):

    template_name = 'form_medicine.html'
    form_class = forms.MedicineForm
    success_url = reverse_lazy('ec_site:list_medicines')

    def get_initial(self):
        initial = super(MedicineFormView, self).get_initial()
        initial['price'] = '2000'
        return initial

    def form_valid(self, form):
        if form.is_valid():
            form.save()
        return super(MedicineFormView, self).form_valid(form)

class MedicineRedirectView(RedirectView):
    url = 'https://shelokuma.com'

    def get_redirect_url(self, *args, **kwargs):
        medicine = Medicines.objects.last()
        if 'pk' in kwargs:
            return reverse_lazy('ec_site:detail_medicine', kwargs={'pk':kwargs['pk']})
        
        return reverse_lazy('ec_site:update_medicine', kwargs={'pk': medicine.pk})

上記を保存し,ブラウザのURLに"http://127.0.0.1:8000/ec_site/update_medicine/5″と入力すると,以下更新ページに遷移する.赤枠の内容(Description, Price)を変更する.

以下赤枠のようにDescriptionとPriceを変更し,"update"をクリックすると,上段の赤枠のメッセージが出力された.メッセージにはNameの内容が引用されている.

  1. 参照

https://docs.djangoproject.com/en/3.2/ref/contrib/messages/#adding-messages-in-class-based-views

以上