Django

Pythonフレームワーク「Django」を利用したアプリで「Bootstrap」を利用してみた

Bootstrapは、WEBページでよく使われるフォーム、ボタン、メニューなどの部品がテンプレートとして用意されているフレームワークで、Bootstrapを利用すると、見栄えのいいWEBサイトを簡単に作成することができる。

今回は、作成済の「Django」を利用したアプリケーションを、「Bootstrap」でデザインしてみたので、そのサンプルプログラムを共有する。

なお、Bootstrapについては、以下のサイトを参照のこと。
https://www.sejuku.net/blog/7407

Bootstrap ダウンロード

Bootstrapは、WEBサイトから無料でダウンロードして利用することができる。その手順は、以下の通り。

1) 以下のサイトにアクセスし、「ダウンロード」ボタンを押下する。
https://getbootstrap.jp

ダウンロード_1

2) 以下の画面に遷移するため、「コンパイルされたCSSとJS」にある「Download」ボタンを押下する。
ダウンロード_2

3)「bootstrap-5.0.2-dist.zip」がダウンロードされるため、解凍する。
ダウンロード_3

4) 今回のサンプルプログラムでは、Bootstrapを解凍したフォルダ内の、「bootstrap.min.css」「bootstrap.bundle.min.js」を利用する。
ダウンロード_4_1

ダウンロード_4_2
「MiniTool Partition Wizard」はパーティション分割・統合・バックアップ・チェックを直感的に行える便利ツールだったハードディスクの記憶領域を論理的に分割し、分割された個々の領域のことを、パーティションといいます。 例えば、以下の図の場合、C/D...

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

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

「bootstrap.min.css」「bootstrap.bundle.min.js」は、ダウンロードしたBootstrapのCSSファイル/JSファイルとなる。

demoフォルダ下、templatesフォルダ下の各画面の内容は以下の通りで、Bootstrapを利用するようにしている。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>一覧画面</title>
    <!-- BootStrap CSS/JSファイルの読み込み -->
    {% load static %}
    <link rel="stylesheet" href="{% static 'demo/css/bootstrap.min.css' %}">
    <script src="{% static 'demo/js/bootstrap.bundle.min.js' %}"></script>
</head>
<body>
    <!-- 画面サイズを画面幅いっぱい(container-fluid)とし、marginを上下左右に設定 -->
    <div class="container-fluid m-4">
        <!-- タイトル行の文字サイズを設定 -->
        <p class="fs-4">ユーザーデータテーブル(user_data)の全データ</p>

        <!-- 表の幅を、画面横幅の11/12の長さに設定 -->
        <div class="col-11">
            <!-- テーブルの1行おきに背景色を設定 -->
            <table class="table table-striped">
                <!-- テーブルのタイトル行を水色に設定 -->
                <tr class="table-info">
                    <th>ID</th>
                    <th>名前</th>
                    <th>生年月日</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>
                    <td>
                        <a href="{% url 'update' user.id %}">更新</a>
                    </td>
                    <td>
                        <a href="{% url 'delete' user.id %}">削除</a>
                    </td>
                </tr>
                {% endfor %}
            </table>
        </div>

        <!-- action属性のURLで、(demoフォルダ内)urls.pyの画面遷移先のname属性の値を指定している -->
        <form action="{% url 'input' %}" method="post">
            <!-- 下記csrf_tokenは、CSRF対策を行うことでform送信時エラーを防ぐために設定 -->
            {% csrf_token %}
            <!-- marginを上に設定 -->
            <div class="mt-5">
                <!-- ボタンの色を青色に設定 -->
                <input type="submit" name="next" value="データ追加" 
                    class="btn btn-primary"/>
            </div>
        </form>
    </div>
</body>
</html>
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>入力画面</title>
    <!-- BootStrap CSS/JSファイルの読み込み -->
    {% load static %}
    <link rel="stylesheet" href="{% static 'demo/css/bootstrap.min.css' %}">
    <script src="{% static 'demo/js/bootstrap.bundle.min.js' %}"></script>
</head>
<body>
    <!-- 画面サイズを画面幅いっぱい(container-fluid)とし、marginを上下左右に設定 -->
    <div class="container-fluid m-4">
        <!-- タイトル行の文字サイズを設定 -->
        <p class="fs-4">下記必要事項を記載の上、「確認」ボタンを押下してください。</p>

        <!-- action属性のURLで、(demoフォルダ内)urls.pyの画面遷移先のname属性の値を指定している -->
        <form action="{% url 'confirm' %}" method="post">
            <!-- 下記csrf_tokenは、CSRF対策を行うことでform送信時エラーを防ぐために設定 -->
            {% csrf_token %}

            <!-- 表の幅を、画面横幅の9/12の長さに設定 -->
            <div class="col-9">
                <!-- テーブルの枠線を非表示に設定 -->
                <table class="table table-borderless">
                    <!-- 名前 -->
                    <tr>
                        <!-- 画面幅が広くなるにつれてラベルのサイズを狭める設定 -->
                        <td class="col-md-4 col-lg-2">
                            <!-- フォームとラベルの関連付けを設定 -->
                            <label for="name" class="form-label">
                                {{ form.name.label_tag }}
                            </label>
                        </td>
                        <td>
                        <span id="name" class="form-label">
                            {{ form.name }}
                        </span>
                        </td>
                    </tr>
                    <!-- 生年月日 -->
                    <tr>
                        <td>{{ form.birth_day.label_tag }}</td>
                        <td>
                            {{ form.birth_year }}年
                            {{ form.birth_month }}月
                            {{ form.birth_day }}日
                            <!-- 生年月日の入力チェックエラーを表示 -->
                            <span class="text-danger">
                                {{ form.non_field_errors.0 }}
                            </span>
                        </td>
                    </tr>
                    <!-- 性別 -->
                    <tr>
                        <td>{{ form.sex.label_tag }}</td>
                        <td>
                            {% for sex_choice in form.sex %}
                            <span class="me-2">
                            {{ sex_choice.choice_label }}
                            {{ sex_choice.tag }}
                        </span>
                            {% endfor %}
                        </td>
                    </tr>
                    <!-- メモ -->
                    <tr>
                        <td>
                            <label for="memo" class="form-label">
                                {{ form.memo.label_tag }}
                            </label>
                        </td>
                        <td>
                        <span id="memo" class="form-label">
                            {{ form.memo }}
                        </span>
                        </td>
                    </tr>
                    <!-- 入力確認 -->
                    <tr>
                        <td>
                            <label for="check" class="form-label">
                                {{ form.check.label_tag }}
                            </label>
                        </td>
                        <td>
                        <span id="check" class="form-label">
                            {{ form.check }}
                        </span>
                        </td>
                    </tr>
                </table>
            </div>

            <!-- ユーザーID -->
            <!-- 一覧画面で更新リンクを押下したため、object.idが設定されている場合 -->
            {% if object.id %}
                <input type="hidden" name="user_id" value="{{ object.id }}"/>
            <!-- 入力画面で入力チェックエラーが発生したり、確認画面で戻るボタンを
                     押下したため、user_idが設定されている場合 -->
            {% elif user_id %}
                <input type="hidden" name="user_id" value="{{ user_id }}"/>
            <!-- 一覧画面でデータ追加ボタンを押下したため、object.idもuser_idも
                     設定されていない場合 -->
            {% else %}
                <input type="hidden" name="user_id" value=""/>
            {% endif %}

            <!-- marginを上に設定 -->
            <div class="mt-5">
                <!-- ボタンの色を青色に設定 -->
                <input type="submit" name="confirm" value="確認" 
                    class="btn btn-primary"/>
                <!-- marginを左に設定 -->
                <span class="ms-4">
                    <input type="button" name="back" value="戻る" 
                        class="btn btn-primary"
                        onclick="location.href={% url 'index' %}"/>
                </span>
            </div>
        </form>
    </div>
</body>
</html>
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>確認画面</title>
    <!-- BootStrap CSS/JSファイルの読み込み -->
    {% load static %}
    <link rel="stylesheet" href="{% static 'demo/css/bootstrap.min.css' %}">
    <script src="{% static 'demo/js/bootstrap.bundle.min.js' %}"></script>
</head>
<body>
    <!-- 画面サイズを画面幅いっぱい(container-fluid)とし、marginを上下左右に設定 -->
    <div class="container-fluid m-4">
        <!-- タイトル行の文字サイズを設定 -->
        <p class="fs-4">入力内容を確認し、問題なければ「送信」ボタンを押下してください。</p>

        <form action="{% url 'regist' %}" method="post">
            {% csrf_token %}

            <!-- 表の幅を、画面横幅の8/12の長さに設定 -->
            <div class="col-8">
                <!-- テーブルの枠線を非表示に設定 -->
                <table class="table table-borderless">
                    <!-- 名前 -->
                    <tr>
                        <!-- 画面幅が広い場合にラベルのサイズを狭める設定 -->
                        <td class="col-md-4 col-lg-2">
                            {{ input_form.name.label_tag }}
                        </td>
                        <td>{{ input_form.name.value }}</td>
                    </tr>
                    <!-- 生年月日 -->
                    <tr>
                        <td>{{ input_form.birth_day.label_tag }}</td>
                        <td>
                            {{ input_form.birth_year.value }}年
                            {{ input_form.birth_month.value }}月
                            {{ input_form.birth_day.value }}日
                        </td>
                    </tr>
                    <!-- 性別 -->
                    <tr>
                        <td>{{ input_form.sex.label_tag }}</td>
                        <td>{{ lbl_sex }}</td>
                    </tr>
                    <!-- メモ -->
                    <tr>
                        <td>{{ input_form.memo.label_tag }}</td>
                        <td>
                            <!-- テキストエリアの改行を有効にするため、「| linebreaksbr」を付与 -->
                            {{ input_form.memo.value | linebreaksbr }}
                        </td>
                    </tr>
                    <!-- 入力確認 -->
                    <tr>
                        <td>{{ input_form.check.label_tag }}</td>
                        <td>{{ lbl_checked }}</td>
                    </tr>
                </table>
            </div>

            <!-- ユーザーID -->
            <input type="hidden" name="user_id" value="{{ user_id }}"/>
            <!-- フォームの各値を次画面に渡すためhidden項目を設定 -->
            {% for field in input_form %}
                {{field.as_hidden}}
            {% endfor %}

            <!-- marginを上に設定 -->
            <div class="mt-5">
                <!-- ボタンの色を青色に設定 -->
                <input type="submit" name="send" 
                    class="btn btn-primary" value="送信"/>
                <!-- marginを左に設定 -->
                <span class="ms-4">
                    <input type="submit" name="back" 
                        class="btn btn-primary" value="戻る"/>
                </span>
            </div>
        </form>
    </div>
</body>
</html>
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>完了画面</title>
    <!-- BootStrap CSS/JSファイルの読み込み -->
    {% load static %}
    <link rel="stylesheet" href="{% static 'demo/css/bootstrap.min.css' %}">
    <script src="{% static 'demo/js/bootstrap.bundle.min.js' %}"></script>
</head>
<body>
    <!-- 画面サイズを画面幅いっぱい(container-fluid)とし、marginを上下左右に設定 -->
    <div class="container-fluid m-4">
        <!-- タイトル行の文字サイズを設定 -->
        <p class="fs-4">お申し込みが完了しました。</p>

        <!-- marginを上に設定 -->
        <div class="mt-5">
            <!-- ボタンの色を青色に設定 -->
            <input type="button" name="back" value="一覧画面に戻る" 
                class="btn btn-primary"
                onclick="location.href={% url 'index' %}"/>
        </div>
    </div>
</body>
</html>
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>削除確認画面</title>
    <!-- BootStrap CSS/JSファイルの読み込み -->
    {% load static %}
    <link rel="stylesheet" href="{% static 'demo/css/bootstrap.min.css' %}">
    <script src="{% static 'demo/js/bootstrap.bundle.min.js' %}"></script>
</head>
<body>
    <!-- 画面サイズを画面幅いっぱい(container-fluid)とし、marginを上下左右に設定 -->
    <div class="container-fluid m-4">
        <!-- タイトル行の文字サイズを設定 -->
        <p class="fs-4">下記データを削除する場合は、「削除」ボタンを押下してください。</p>

        <form method="post">
            <!-- 下記csrf_tokenは、CSRF対策を行うことでform送信時エラーを防ぐために設定 -->
            {% csrf_token %}

            <!-- 表の幅を、画面横幅の8/12の長さに設定 -->
            <div class="col-8">
                <!-- テーブルの枠線を非表示に設定 -->
                <table class="table table-borderless">
                    <!-- 名前 -->
                    <tr>
                        <!-- 画面幅が広い場合にラベルのサイズを狭める設定 -->
                        <td class="col-md-4 col-lg-2">
                            名前:
                        </td>
                        <td>{{ object.name }}</td>
                    </tr>
                    <!-- 生年月日 -->
                    <tr>
                        <td>生年月日:</td>
                        <td>
                            {{ object.birth_year }}年
                            {{ object.birth_month }}月
                            {{ object.birth_day }}日
                        </td>
                    </tr>
                    <!-- 性別 -->
                    <tr>
                        <td>性別:</td>
                        <td>
                            {% if object.sex|stringformat:"s" == "1" %}
                                男
                            {% elif object.sex|stringformat:"s" == "2" %}
                                女
                            {% endif %}
                        </td>
                    </tr>
                    <!-- メモ -->
                    <tr>
                        <td>メモ:</td>
                        <td>
                            <!-- 「| default:""」で、Noneを空文字に置き換える -->
                            <!-- テキストエリアの改行を有効にするため、「| linebreaksbr」を付与 -->
                            {{ object.memo | default:"" | linebreaksbr }}
                        </td>
                    </tr>
                </table>
            </div>

            <!-- marginを上に設定 -->
            <div class="mt-5">
                <!-- 削除ボタンの色を赤色に設定 -->
                <input type="submit" value="削除" class="btn btn-danger"/>
                <!-- marginを左に設定 -->
                <span class="ms-4">
                    <!-- 戻るボタンの色を青色に設定 -->
                    <input type="button" name="back" value="戻る" 
                        class="btn btn-primary"
                        onclick="location.href={% url 'index' %}"/>
                </span>
            </div>
        </form>
    </div>
</body>
</html>

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



「CODE×CODE」は、需要の高い技術(AWS, Python等)を習得できるプログラミングスクールスクールだった近年、さまざまな会社でクラウド(特にIaaSやPaaSのパブリッククラウド)の需要が非常に高まっていて、クラウドサービスによるシステム開...

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

サンプルプログラムの実行結果は以下の通りで、各画面がBootstrapでデザインされていることが確認できる。

1) 実行前のuser_dataテーブルの中身は、以下の通り。

select * from user_data
サンプルプログラムの実行結果_1

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

3) Webブラウザを起動し、「http://127.0.0.1:8000/demo/」にアクセスすると、以下のように、user_dataテーブルの中身が一覧画面(list.html)に表示されることが確認できる。
サンプルプログラムの実行結果_3

4) 上記画面で「データ追加」ボタンを押下すると、以下のように、入力画面(input.html)が表示されることが確認できる。
サンプルプログラムの実行結果_4

5) 入力画面(input.html)でエラーが発生した場合のレイアウトは、以下の通り。
サンプルプログラムの実行結果_5

6) 確認画面(confirm.html)のレイアウトは、以下の通り。
サンプルプログラムの実行結果_6

7) 完了画面(complete.html)のレイアウトは、以下の通り。
サンプルプログラムの実行結果_7

8) 一覧画面(list.html)で、ID=4の「更新」リンクを押下すると、以下のように、該当するデータが入力画面に表示されることが確認できる。
サンプルプログラムの実行結果_8_1

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

9) 一覧画面(list.html)で、ID=4の「削除」リンクを押下すると、以下のように、該当するデータが削除確認画面に表示されることが確認できる。
サンプルプログラムの実行結果_9_1

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

要点まとめ

  • Bootstrapは、WEBページでよく使われるフォーム、ボタン、メニューなどの部品がテンプレートとして用意されているフレームワークで、Bootstrapを利用すると、見栄えのいいWEBサイトを簡単に作成することができる。
  • Pythonフレームワーク「Django」を利用したアプリケーションでも、「Bootstrap」を利用できる。