Pythonフレームワーク「Django」には、一覧画面を表示する際に利用する「ListView」というクラスベースビューがある。
今回は、MySQLのデータベースのテーブルのユーザーを一覧に表示する機能を追加してみたので、そのサンプルプログラムを共有する。
なお、クラスベースビューについては、以下のサイトを参照のこと。
https://di-acc2.com/programming/python/5210/
前提条件
下記記事の実装が完了していること。
サンプルプログラムの作成
作成したサンプルプログラムの構成は、以下の通り。
なお、上記の赤枠は、前提条件のプログラムから追加・変更したプログラムである。
demoフォルダ下、templatesフォルダ下の一覧画面(list.html)の内容は以下の通りで、user_dataテーブルから取得したユーザーデータを一覧で表示すると共に、入力画面に遷移するための「データ追加」ボタンを表示している。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>一覧画面</title> </head> <body> ユーザーデータテーブル(user_data)の全データ<br/><br/> <table border="1" cellpadding="5"> <tr> <th>ID</th> <th>名前</th> <th>生年月日</th> <th>性別</th> </tr> <!-- context_object_nameで指定した一覧取得結果を画面に表示 --> {% for user in user_list %} <tr> <td>{{ user.id }}</td> <td>{{ user.name }}</td> <td>{{ user.birth_year }}年 {{ user.birth_month }}月 {{ user.birth_day }}日</td> <td> {% if user.sex|stringformat:"s" == "1" %} 男 {% elif user.sex|stringformat:"s" == "2" %} 女 {% endif %} </td> </tr> {% endfor %} </table> <br/><br/> <!-- action属性のURLで、(demoフォルダ内)urls.pyの画面遷移先のname属性の値を指定している --> <form action="{% url 'input' %}" method="post"> <!-- 下記csrf_tokenは、CSRF対策を行うことでform送信時エラーを防ぐために設定 --> {% csrf_token %} <input type="submit" name="next" value="データ追加" /> </form> </body> </html> |
また、demoフォルダ下、templatesフォルダ下の入力画面(input.html)の内容は以下の通りで、一覧画面(list.html)に遷移するための「戻る」ボタンを追加している。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>入力画面</title> <!-- 独自CSSファイルの読み込み --> {% load static %} <link rel="stylesheet" href="{% static 'demo/css/demo.css' %}"> </head> <body> <p>下記必要事項を記載の上、「確認」ボタンを押下してください。</p><br/> <!-- action属性のURLで、(demoフォルダ内)urls.pyの画面遷移先のname属性の値を指定している --> <form action="{% url 'confirm' %}" method="post"> <!-- 下記csrf_tokenは、CSRF対策を行うことでform送信時エラーを防ぐために設定 --> {% csrf_token %} <table> <!-- 氏名 --> <tr> <td align="left" valign="top">{{ input_form.name.label_tag }}</td> <td>{{ input_form.name }}</td> </tr> <!-- 生年月日 --> <tr> <td align="left" valign="top"> {{ input_form.birth_day.label_tag }} </td> <td> {{ input_form.birth_year }}年 {{ input_form.birth_month }}月 {{ input_form.birth_day }}日 <!-- 生年月日の入力チェックエラーを表示 --> <span class="error_message"> {{ input_form.non_field_errors.0 }} </span> </td> </tr> <!-- 性別 --> <tr> <td align="left" valign="top">{{ input_form.sex.label_tag }}</td> <td> {% for sex_choice in input_form.sex %} {{ sex_choice.choice_label }} {{ sex_choice.tag }} {% endfor %} </td> </tr> <!-- メモ --> <tr> <td align="left" valign="top">{{ input_form.memo.label_tag }}</td> <td>{{ input_form.memo }}</td> </tr> <!-- 入力確認 --> <tr> <td align="left" valign="top">{{ input_form.check.label_tag }}</td> <td>{{ input_form.check }}</td> </tr> </table> <br/><br/> <input type="submit" name="confirm" value="確認" /> <input type="button" name="back" value="戻る" onclick="location.href={% url 'index' %}" /> </form> </body> </html> |
さらに、demoフォルダ下、templatesフォルダ下の完了画面(complete.html)の内容は以下の通りで、一覧画面(list.html)に遷移するための「一覧画面に戻る」ボタンを追加している。
1 2 3 4 5 6 7 8 9 10 11 12 13 | <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>完了画面</title> </head> <body> お申し込みが完了しました。 <br/><br/> <input type="button" name="back" value="一覧画面に戻る" onclick="location.href={% url 'index' %}" /> </body> </html> |
また、demoフォルダ下、views.pyの内容は以下の通りで、一覧画面(list.html)を表示するListViewクラスを継承したViewクラスと、一覧画面から入力画面(input.html)にpostリクエストで遷移する処理を追加している。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | from django.shortcuts import render from .forms import InputModelForm from .models import UserData from django.db.models import Max from datetime import datetime as dt from django.views.generic import TemplateView from django.views.generic import FormView from django.urls import reverse_lazy from django.views.generic import ListView # クラス定数を定義 SEX_LABEL_IDX = 1 # 性別のラベルを取得するためのインデックス class UserListView(ListView): """ 一覧画面を表示するView """ template_name = 'demo/list.html' # 一覧画面のHTML model = UserData # UserDataモデル(user_dataテーブルと紐づける) context_object_name = 'user_list' # 一覧取得結果 class InputView(TemplateView): """ 入力画面を表示するView """ template_name = 'demo/input.html' def get_context_data(self): """ 入力画面に渡すフォーム値を初期化 """ context = super().get_context_data() context['input_form'] = InputModelForm() return context def post(self, request): """ 入力画面にpostリクエストで遷移 """ return render(request, self.template_name, self.get_context_data()) class ConfirmView(FormView): """ 入力画面で確認ボタンが押下された時の処理を定義するView """ template_name = 'demo/input.html' # form_invalidメソッド実行時に表示する画面 form_class = InputModelForm # 利用するFormクラス success_url = 'demo/confirm.html' # form_validメソッド実行時の画面遷移先 def get_context_data(self, form): """ 入力チェックエラー時に、入力画面にフォーム値を渡す """ context = super().get_context_data() context['input_form'] = form return context def form_valid(self, form): """ フォームの入力チェックを行い、エラーがない場合 """ # 確認画面で表示するための入力値(性別)の値を生成 lbl_sex = UserData.sex_data[int(form.cleaned_data['sex']) - 1][SEX_LABEL_IDX] # 確認画面に渡す各変数を定義し、確認画面に遷移 context = { 'input_form': form, 'lbl_sex': lbl_sex, 'lbl_checked': '確認済' } return render(self.request, self.success_url, context) def form_invalid(self, form): """ フォームの入力チェックを行い、エラーがある場合 """ # フォーム値はそのままで入力画面に戻る return super().form_invalid(form) class RegistView(FormView): """ 確認画面でボタンが押下された時の処理を定義するView """ template_name = 'demo/input.html' # 戻るボタン押下時に表示する画面 form_class = InputModelForm # 利用するFormクラス success_url = reverse_lazy('complete') # 送信ボタン押下後の画面遷移先 def get_context_data(self, form): """ 戻るボタン押下時に、入力画面にフォーム値を渡す """ context = super().get_context_data() context['input_form'] = form return context def form_valid(self, form): # 送信ボタンが押下された場合 if "send" in self.request.POST: # USER_DATAテーブルに登録されているidの最大値を取得 max_id_dict = UserData.objects.all().aggregate(Max('id')) # USER_DATAテーブルに入力データを追加 # USER_DATAテーブルに登録されているデータが無い場合、id=1とする user_data = UserData() user_data.id = (max_id_dict['id__max'] or 0) + 1 # 確認画面でのフォーム値にidを設定し、入力データを保存 input_form = InputModelForm(self.request.POST, instance=user_data) input_form.save() # 完了画面に遷移 return super().form_valid(form) # 戻るボタンが押下された場合 elif "back" in self.request.POST: # 確認画面でのフォーム値を入力画面に渡す return super().form_invalid(form) class CompleteView(TemplateView): """ 完了画面を表示するView """ template_name = 'demo/complete.html' |
さらに、demoフォルダ下、urls.pyの内容は以下の通りで、一覧画面(list.html)を表示するパスを追加し、入力画面(input.html)へのパスを修正している。
1 2 3 4 5 6 7 8 9 10 | from django.urls import path from . import views urlpatterns = [ path('', views.UserListView.as_view(), name='index'), path('input', views.InputView.as_view(), name='input'), path('confirm', views.ConfirmView.as_view(), name='confirm'), path('regist', views.RegistView.as_view(), name='regist'), path('complete', views.CompleteView.as_view(), name='complete'), ] |
その他のソースコード内容は、以下のサイトを参照のこと。
https://github.com/purin-it/python/tree/master/django-listview/djangoApp
サンプルプログラムの実行
サンプルプログラムの実行結果は以下の通りで、user_dataテーブルから取得したユーザーデータが一覧画面に表示されることが確認できる。
1) 実行前のuser_dataテーブルの中身は、以下の通り。
1 | select * from user_data |
2) コマンドプロンプトでDjangoプロジェクト名のフォルダに移動し、コマンドプロンプトで「python manage.py runserver」コマンドを実行して、Webサーバーを起動する。
3) Webブラウザを起動し、「http://127.0.0.1:8000/demo/」にアクセスすると、以下のように、user_dataテーブルの中身が一覧画面(list.html)に表示されることが確認できる。ここで「データ追加」ボタンを押下する。
4) 以下のように、入力画面の表示が確認できる。ここで「戻る」ボタンを押下する。
5) 以下のように、一覧画面(list.html)に戻ることが確認できる。
6) 入力画面(input.html)、確認画面(confirm.html)、完了画面(complete.html)の遷移は以下の通りで、前提条件の記事と同じ内容となっている。また、完了画面で「一覧画面に戻る」ボタンを押下すると、一覧画面(list.html)に戻り、登録したデータが表示されることが確認できる。
7) 実行後のuser_dataテーブルの中身は以下の通りで、登録したデータが追加されていることが確認できる。
1 | select * from user_data |
要点まとめ
- Pythonフレームワーク「Django」には、データベースのテーブルの内容を一覧表示するのに便利な「ListView」というクラスベースビューがある。