Django

Pythonフレームワーク「Django」を利用して複数画面をもつWebアプリケーションを作成してみた

Django(ジャンゴ)を利用すると、PythonによるWebアプリケーションを作成することができる。

今回は、入力画面・確認画面・完了画面の3画面を含み、HTMLオブジェクトとしてテキストボックス・ラジオボタン・チェックボックス等を含むWEBアプリケーションを作成してみたので、そのサンプルプログラムを共有する。

前提条件

下記記事のDjangoによる環境構築と実装が完了していること。

Pythonフレームワーク「Django」を利用したWebアプリケーションを作成してみたDjango(ジャンゴ)とは、Pythonで開発する際のWebフレームワークの1つで、無料のオープンソースとして公開されていて、高品質な...

サンプルプログラムの作成

作成したサンプルプログラムの構成は、以下の通り。
サンプルプログラムの構成
なお、上記の赤枠は、前提条件のプログラムから追加・変更したプログラムである。

djangoAppフォルダ下、settings.pyの変更内容は以下の通りで、言語設定を日本語に変更している。

# 設定を日本語に変更
LANGUAGE_CODE = 'ja'

TIME_ZONE = 'Asia/Tokyo'

また、demoフォルダ下、templatesフォルダ下のHTMLファイルの内容は以下の通りで、入力画面(input.html)・確認画面(confirm.html)・完了画面(complete.html)を作成している。

<!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_day }}
                    <!-- 生年月日の入力チェックエラーを表示 -->
                    <span class="error_message">
                        {{ input_form.birth_day.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="確認" />
    </form>
</body>
</html>
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>確認画面</title>
</head>
<body>
    <p>入力内容を確認し、問題なければ「送信」ボタンを押下してください。</p>
    <form action="{% url 'regist' %}" method="post">
        {% csrf_token %}
        <table>
            <!-- 氏名 -->
            <tr>
                <td align="left" valign="top">{{ input_form.name.label_tag }}</td>
                <td>{{ input_form.name.value }}</td>
            </tr>
            <!-- 生年月日 -->
            <tr>
                <td align="left" valign="top">
                    {{ input_form.birth_day.label_tag }}
                </td>
                <td>{{ lbl_birth_day }}</td>
            </tr>
            <!-- 性別 -->
            <tr>
                <td align="left" valign="top">{{ input_form.sex.label_tag }}</td>
                <td>{{ lbl_sex }}</td>
            </tr>
            <!-- メモ -->
            <tr>
                <td align="left" valign="top">{{ input_form.memo.label_tag }}</td>
                <!-- テキストエリアの改行を有効にするため、「| linebreaksbr」を付与 -->
                <td>{{ input_form.memo.value | linebreaksbr }}</td>
            </tr>
            <!-- 入力確認 -->
            <tr>
                <td align="left" valign="top">{{ input_form.check.label_tag }}</td>
                <td>{{ lbl_checked }}</td>
            </tr>
        </table>
        <br/><br/>
        <!-- フォームの各値を次画面に渡すためhidden項目を設定 -->
        {% for field in input_form %}
             {{field.as_hidden}}
        {% endfor %}
        <input type="submit" name="send" value="送信" />
        <input type="submit" name="back" value="戻る" />
    </form>
</body>
</html>
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>完了画面</title>
</head>
<body>
    お申し込みが完了しました。
</body>
</html>

さらに、demoフォルダ下、staticフォルダ下のCSSファイルの内容は以下の通りで、入力画面で利用している。

.error_message{
    color: #FF0000;
}

また、demoフォルダ下、forms.pyの内容は以下の通りで、入力画面で利用するフォームオブジェクトを定義している。

from django import forms


class InputForm(forms.Form):
    sex_data = [
        ('1', '男'),
        ('2', '女')
    ]
    name = forms.CharField(label='名前', max_length=13)
    birth_day = forms.DateField(label='生年月日'
                    , widget=forms.SelectDateWidget(years=range(1910, 2023))
                    , initial='2012-01-01')
    sex = forms.ChoiceField(label='性別', choices=sex_data
                    , widget=forms.RadioSelect())
    memo = forms.CharField(label='メモ'
                    , widget=forms.Textarea(attrs={'rows': 6, 'cols': 40})
                    , required=False)
    check = forms.BooleanField(label='入力確認')

なお、日付の入力項目はSelectDateWidgetで生成している。また、日付の妥当性チェックや「required=False」属性の無い項目の必須チェックも、自動で実施されるようになっている。

さらに、demoフォルダ下、urls.pyの内容は以下の通りで、入力画面・確認画面・完了画面の画面遷移時に呼び出すURLパスを指定している。

from django.urls import path
from . import views

urlpatterns = [
    path('', views.index, name='index'),
    path('confirm', views.confirm, name='confirm'),
    path('regist', views.regist, name='regist'),
]

また、demoフォルダ下、views.pyの内容は以下の通りで、各画面でボタンが押下された場合の処理を定義している。

from django.shortcuts import render
from django.http import HttpResponse
from .forms import InputForm

# クラス定数を定義
SEX_LABEL_IDX = 1  # 性別のラベルを取得するためのインデックス


def index(request):
    """ 入力画面を表示 """
    # 確認画面に渡すフォームを初期化
    params = {
        'input_form': InputForm()
    }
    return render(request, 'demo/input.html', params)


def confirm(request):
    """ 入力画面で確認ボタンが押下された時の処理を定義 """
    # 入力画面でのフォーム値を取得し
    input_form = InputForm(request.POST)

    # フォームの入力チェックを行い、エラーがない場合
    if input_form.is_valid():
        # 確認画面で表示するための入力値(生年月日・性別)の値を生成
        lbl_birth_day = request.POST['birth_day_year'] + '年' \
                        + request.POST['birth_day_month'] + '月' \
                        + request.POST['birth_day_day'] + '日'
        lbl_sex = input_form.sex_data[int(request.POST['sex']) - 1][SEX_LABEL_IDX]

        # 確認画面に渡す各変数を定義
        params = {
            'input_form': input_form,
            'lbl_birth_day': lbl_birth_day,
            'lbl_sex': lbl_sex,
            'lbl_checked': '確認済'
        }
        return render(request, 'demo/confirm.html', params)

    # フォームの入力チェックを行い、エラーがある場合
    else:
        # フォーム値はそのままで入力画面に戻る
        params = {
            'input_form': input_form
        }
        return render(request, 'demo/input.html', params)


def regist(request):
    """ 確認画面でボタンが押下された時の処理を定義 """
    # 送信ボタンが押下された場合
    if "send" in request.POST:
        # 将来的に、ここにDB登録処理を実装する予定
        return render(request, 'demo/complete.html')

    # 戻るボタンが押下された場合
    elif "back" in request.POST:
        # 確認画面でのフォーム値を入力画面に渡す
        input_form = InputForm(request.POST)
        params = {
            'input_form': input_form
        }
        return render(request, 'demo/input.html', params)

その他のソースコード内容は、以下のサイトを参照のこと。
https://github.com/purin-it/python/tree/master/make-django-web-somescreen/djangoApp

なお、今回は利用していないが、以下のサイトのように、フォームのas_p, as_ul, as_tableを利用できる場合は利用すると、簡単なソースコードでフォーム値の表示をきれいに行える。
https://www.nblog09.com/w/2019/04/09/django_form/



「FlexClip」はテンプレートとして利用できる動画・画像・音楽などが充実した動画編集ツールだったテンプレートとして利用できるテキスト・動画・画像・音楽など(いずれも著作権フリー)が充実している動画編集ツールの一つに、「FlexCli...

サンプルプログラムの実行結果

サンプルプログラムの実行結果は以下の通りで、画面遷移やエラーチェック処理が行えることが確認できる。

1) コマンドプロンプトでDjangoプロジェクト名のフォルダに移動し、「python manage.py runserver」コマンドを実行して、Webサーバーを起動する。
サンプルプログラムの実行結果_1

2) Webブラウザを起動し、「http://127.0.0.1:8000/demo/」にアクセスすると、以下のように、入力画面(input.html)の内容が画面表示されることが確認できる。
サンプルプログラムの実行結果_2

3) 何も入力せず「確認」ボタンを押下すると、以下のようなエラーメッセージが表示されることが確認できる。なお、下記は「名前」の例だが、「性別」「入力確認」も同様のエラーメッセージが表示される。
サンプルプログラムの実行結果_3

4) 生年月日に存在しない日付を入力し「確認」ボタンを押下すると、以下のようなエラーメッセージが表示されることが確認できる。
サンプルプログラムの実行結果_4

5) 以下のように、エラーにならないデータを指定し「確認」ボタンを押下すると、確認画面に入力画面の内容が表示される。さらに「戻る」ボタンを押下すると、入力画面に戻り入力値が復旧されることが確認できる。
サンプルプログラムの実行結果_5_1

サンプルプログラムの実行結果_5_2 サンプルプログラムの実行結果_5_3

6) 以下のように、メモを入力しないで「確認」ボタンを押下した場合も、確認画面に入力画面の内容が表示される。さらに「送信」ボタンを押下すると、完了画面に遷移することが確認できる。
サンプルプログラムの実行結果_6_1

サンプルプログラムの実行結果_6_2 サンプルプログラムの実行結果_6_3

要点まとめ

  • Pythonフレームワーク「Django」には、HTML のフォームを生成するためのFormクラスが用意されていて、入力値のチェックを行う機能も含まれている。
  • 画面遷移時のパスは、HTML formタグ内のaction属性のURLで、urls.pyに定義した画面遷移先のname属性の値を指定する。
  • Djangoでは、デフォルトでCSRFの検証を行うため、POSTメソッドでフォームを送信する場合は「{% csrf_token %}」というタグを追加する必要がある。
  • view.pyで、POSTメソッドで送信されたフォームの値を取得するには、requestオブジェクトのPOSTメソッドを利用する。
  • view.pyでフォームの入力チェック結果を取得するには、Formクラスのis_validメソッドを利用する。