11-Flask

Flask(Part.16)| 【見た目の統一化(2)】

python| まとめ | 現役エンジニア&プログラミングスクール講師「python」のまとめページです。pythonに関して抑えておきたい知識や文法やにについて記事をまとめています。まとめページの下部には「おすすめの学習書籍」「おすすめのITスクール情報」「おすすめ求人サイト」について情報を掲載中...

目標

  • 共通テンプレートを作成して管理を行いやすくする。

Flaskアプリケーションのレイアウト

共通テンプレートの概要

Flaskでは、Jinja2 というテンプレートエンジンを使用してHTMLを動的に生成します。このとき、複数のページで共通する部分(ヘッダー、フッター、ナビゲーションバーなど)をまとめた、「親テンプレート」と呼ばれる、ひとつのテンプレートを作成し、
「子テンプレート」と呼ばれる個別ページのテンプレートに「継承」して使うことができます。この仕組みによって、コードの重複を減らし、メンテナンスがしやすくなります。

共通テンプレートの実装手順

共通テンプレートの利用は次のような手順で行います。

  1. 共通テンプレート(base.html)を作成する。
    • 共通テンプレートにはヘッダー、ナビゲーションバー、フッターなどを定義します。
    • block タグを使い、個別ページごとに内容を差し替え可能にします。
  2. 個別ページのテンプレート(products.html や categories.html など)で base.html を継承します。
    • block の中に、それぞれのページ固有のコンテンツを記述します。

base.htmlの作成

templatesディレクトリの中に、全てのテンプレートで利用されるヘッダーやフッターなどを定義したbase.html(親テンプレート)を作成します。templatesディレクトリを右クリックして新しいファイルを作成し、名前をbase.htmlとします。

base.htmlに次のように入力します。

<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>
        {% block title %}
        <!-- 個別ページのタイトルがここに入る -->
        {% endblock %}
    </title>
    <link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
</head>

<body>

    <header>
        {% block header %}
        <!-- 個別ページのヘッダーがここに入る -->
        {% endblock %}
    </header>

    <main>
        {% block content %}
        <!-- 個別ページのコンテンツがここに入る -->
        {% endblock %}
    </main>

    <footer>
        <p>© 2025 howahowa store</p>
    </footer>
</body>

</html>

manage_products.htmlの編集

base.htmlを継承し、利用するため、manage_products.htmlなどの個別ページではbase.htmlのblockに埋め込む部分だけを準備します。

よって、次のようなbase.htmlでも記述のある部分は削除します。

<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{{ title }}</title>
    <link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
</head>

変更後の manage_products.html は次の通りです。

manage_products.html
{% extends "base.html" %}

{% block title %}{{ title }}{% endblock %}

{% block header %}
<h1>{{ title }}</h1>
<ul>
    <li><a href="{{ url_for('product_list') }}" class="button-link">商品一覧</a></li>
    <li><a href="{{ url_for('add_product') }}" class="button-link">商品追加</a></li>
    <li><a href="{{ url_for('category_list') }}" class="button-link">カテゴリ一覧</a></li>
    <li><a href="{{ url_for('add_category') }}" class="button-link">カテゴリ追加</a></li>
</ul>
{% endblock %}
style.css

スタイルシートにheaderタグ、mainタグ、footerタグ部分のスタイルを追加します。

header {
    margin: 0;
    padding: 10px 0;
}

main {
    margin: 0;
    padding: 20px;
}

footer {
    background-color: #aaa;
    color: white;
    text-align: center;
    padding: 10px 0;
    margin-top: 20px;
}

続けてスタイルシートのulセレクタ、ul:first-of-typeセレクタ、ul:first-of-type liセレクタ、liセレクタ部分にheaderを追記し、「header ul」のように編集します。

  • ul → header li
  • ul:first-of-type → header ul:first-of-type
  • ul:first-of-type li → header ul:first-of-type li
  • li → header li
/* ボタン部分のリストを横並びにする */
header ul,
main ul {
    padding: 0;
}

header ul:first-of-type {
    display: flex;
    /* 横並び */
    justify-content: flex-start;
    /* 左寄せ */
}

header ul:first-of-type li {
    margin-right: 10px;
    /* ボタン間に余白 */
}

/* リストアイテムの基本スタイル */
header li {
    list-style-type: none;
    /* デフォルトのリストスタイルを削除 */
}

変更後の表示

{% extends “base.html” %}

base.htmlを継承します。(base.htmlを利用可能にします。)

{% block title %}{{ title }}{% endblock %}

base.htmlの次の箇所に取り込まれます。

{% block title %}
<!-- 個別ページのタイトルがここに入る -->
{% endblock %}
{% block header %}{% endblock %}

base.htmlの次の箇所に取り込まれます。

{% block header %}
<!-- 個別ページのコンテンツがここに入る -->
{% endblock %}

products.htmlの編集

products.htmlを次のように編集します。

products.html
{% extends "base.html" %}

{% block title %}{{ title }}{% endblock %}

{% block header %}
<ul>
    <li><a href="{{ url_for('manage_products') }}" class="button-link">商品管理ページ</a></li>
    <li><a href="{{ url_for('add_product') }}" class="button-link">商品を追加する</a></li>
</ul>
{% endblock %}

{% block content %}
<h1>{{ title }}</h1>
{% for category, products in grouped_products.items() %}
<h2>{{ category }}</h2>
<ul class="product-list">
    {% for product in products %}
    <li class="product-item">
        <span class="product-name">{{ product.name }} : ¥{{ "{:,}".format(product.price) }}</span>
        <div class="button-group">
            <form action="{{ url_for('edit_product', product_id=product.id) }}" method="GET" style="display:inline;">
                <button type="submit" class="edit-button">編集</button>
            </form>
            <form action="{{ url_for('delete_product', product_id=product.id) }}" method="POST" style="display:inline;">
                <button type="submit" class="delete-button"
                    onclick="return confirm('本当に削除しますか?※既に注文で利用されている場合は削除できません。')">削除</button>
            </form>
        </div>
    </li>
    {% endfor %}
</ul>
{% endfor %}
{% endblock %}

変更後の表示

products_form.htmlの編集

product_form.html
{% extends "base.html" %}

{% block title %}{{ title }}{% endblock %}

{% block header %}
<ul>
    <li><a href="{{ url_for('manage_products') }}" class="button-link">商品管理ページ</a></li>
    <li><a href="{{ url_for('product_list') }}" class="button-link">商品一覧に戻る</a></li>
</ul>
{% endblock %}
{% block content %}
<h1>{{ title }}</h1>

<form method="POST" action="{{ url_for('add_product') }}">
    {{ form.hidden_tag() }} <!-- CSRFトークンを含めるため -->

    <label for="product_name">商品名</label>
    {{ form.product_name() }} <!-- 商品名入力フィールド -->
    {% if form.product_name.errors %}
    <ul>
        {% for error in form.product_name.errors %}
        <li>{{ error }}</li>
        {% endfor %}
    </ul>
    {% endif %}

    <label for="product_price">価格</label>
    {{ form.product_price() }} <!-- 価格入力フィールド -->
    {% if form.product_price.errors %}
    <ul>
        {% for error in form.product_price.errors %}
        <li>{{ error }}</li>
        {% endfor %}
    </ul>
    {% endif %}

    <label for="category">カテゴリー</label>
    {{ form.category() }}
    {% if form.category.errors %}
    <ul>
        {% for error in form.category.errors %}
        <li>{{ error }}</li>
        {% endfor %}
    </ul>
    {% endif %}

    <input type="submit" value="商品を登録する">
</form>
{% endblock %}

変更後の表示

categories.htmlの編集

categories.html
{% extends "base.html" %}

{% block title %}{{ title }}{% endblock %}

{% block header %}
<ul>
    <li><a href="{{ url_for('manage_products') }}" class="button-link">商品管理ページ</a></li>
    <li><a href="{{ url_for('add_category') }}" class="button-link">カテゴリーを追加</a></li>
</ul>
{% endblock %}
{% block content %}
<h1>{{ title }}</h1>
<ul>
    {% for category in categories %}
    <li class="category-item">
        <span class="category-name">{{ category.name }}</span>
        <div class="button-group">
            <form action="{{ url_for('edit_category', category_id=category.id) }}" method="GET">
                <button type="submit" class="edit-button">編集</button>
            </form>
            <form action="{{ url_for('delete_category', category_id=category.id) }}" method="POST">
                <button type="submit" class="delete-button"
                    onclick="return confirm('本当に削除しますか?※既に商品が存在する場合は削除できません。')">削除</button>
            </form>
        </div>
    </li>
    {% endfor %}
</ul>
{% endblock %}

変更後の表示

category_form.htmlの編集

category_form.html
{% extends "base.html" %}

{% block title %}{{ title }}{% endblock %}

{% block header %}
<ul>
    <li><a href="{{ url_for('manage_products') }}" class="button-link">商品管理ページ</a></li>
    <li><a href="{{ url_for('category_list') }}" class="button-link">カテゴリー一覧ページ</a></li>
</ul>
{% endblock %}
{% block content %}
<h1>{{ title }}</h1>
<form method="POST">
    {{ form.hidden_tag() }}
    <label for="name">カテゴリー名</label>
    {{ form.name() }}
    {% for error in form.name.errors %}
    <p style="color: red;">{{ error }}</p>
    {% endfor %}
    {{ form.submit(class="button-link") }}
</form>
{% endblock %}

変更後の表示

今回は以上になります。

「python」おすすめ書籍 ベスト3 | 現役エンジニア&プログラミングスクール講師「python」の学習でお勧めしたい書籍をご紹介しています。お勧めする理由としては、考え方、イメージなどを適切に捉えていること、「生のpython」に焦点をあてて解説をしている書籍であることなどが理由です。勿論、この他にも良い書籍はありますが、特に質の高かったものを選んで記事にしています。ページの下部には「おすすめのITスクール情報」「おすすめ求人サイト」について情報を掲載中。...

ブックマークのすすめ

「ほわほわぶろぐ」を常に検索するのが面倒だという方はブックマークをお勧めします。ブックマークの設定は別記事にて掲載しています。

「お気に入り」の登録・削除方法【Google Chrome / Microsoft Edge】「お気に入り」の登録・削除方法【Google Chrome / Microsoft Edge】について解説している記事です。削除方法も掲載しています。...
【パソコン選び】失敗しないための重要ポイント | 現役エンジニア&プログラミングスクール講師【パソコン選び】失敗しないための重要ポイントについての記事です。パソコンのタイプと購入時に検討すべき点・家電量販店で見かけるCPUの見方・購入者が必要とするメモリ容量・HDDとSSDについて・ディスプレイの種類・バッテリーの持ち時間や保証・Officeソフト・ウィルス対策ソフトについて書いています。...
RELATED POST
11-Flask

Flask(Part.2)| 【MVTの概要とアプリケーションの起動方法 】

2025年2月13日
プログラミング学習 おすすめ書籍情報発信 パソコン初心者 エンジニア希望者 新人エンジニア IT業界への就職・転職希望者 サポートサイト Programming learning Recommended schools Recommended books Information dissemination Computer beginners Prospective engineers New engineers Prospective job seekers in the IT industry Support site
11-Flask

Flask(Part.8)| 【Flaskでデータベースを利用する方法(1) 実装】

2025年3月1日
プログラミング学習 おすすめ書籍情報発信 パソコン初心者 エンジニア希望者 新人エンジニア IT業界への就職・転職希望者 サポートサイト Programming learning Recommended schools Recommended books Information dissemination Computer beginners Prospective engineers New engineers Prospective job seekers in the IT industry Support site
11-Flask

Flask(Part.9)| 【Flaskでデータベースを利用する方法(2)解説】

2025年3月2日
プログラミング学習 おすすめ書籍情報発信 パソコン初心者 エンジニア希望者 新人エンジニア IT業界への就職・転職希望者 サポートサイト Programming learning Recommended schools Recommended books Information dissemination Computer beginners Prospective engineers New engineers Prospective job seekers in the IT industry Support site