0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

MacBookでのFlask開発環境セットアップ

Last updated at Posted at 2024-12-17

手持ちのMacBookPro でFlask開発をする環境をセットアップするためのメモ

環境

  • MacBookPro 13-inch 2020 Intel Core i7
  • Flask 3.0.3
  • pip 23.0.1

1.準備

1.1 treeコマンドインストール

  • MacBookに homebrewでtreeコマンドを入れる。時々階層表示で確認したいため
$ brew install tree

簡単な使い方

terminal
# 確認したい階層のフォルダに移動してから
tree
# 現在のディレクトリから2階層目まで表示
$ tree -L 2
# .env等も表示したい場合(-a)
$ tree -a
$ tree -aL 2
# ターミナル表示されたものをコピー
$ tree -L 2 | pbcopy
# テキストエディット開いて貼り付け

1.2.開発環境の階層を決める

  • 例えばこんな感じ
terminal
# プロジェクトフォルダの階層に移動
cd pj05_test
# treeコマンド実行
# .DS_Storeなどは消してます
pj05_test% tree -a
.
├── .venv_pj05 # venv環境(pip listでの確認用)
|
├── flaskapp
│   ├── .env # 開発環境と本番環境で内容が異なる
│   │
│   ├── app.py
│   ├── views.py
│   │
│   │   # 以下は開発の必要に応じて追加していく
│   ├── generate_cy.py
│   ├── generate_elements_cy.py
│   ├── requirements.txt
│   │
│   ├── static
│   │   ├── css
│   │   │   ├── style.css #とりあえず1つ
│   │   │   └── 必要に応じて増やす
│   │   ├── csvdata # CSVを読み込んだものを表示したい場合
│   │   │   ├── dammy_data.csv
│   │   │   
│   │   ├── images #表示させたい適当な画像
│   │   │   ├── default_item.png
│   │   │   └── default_user.png
│   │   └── js
│   │       └── sample.js #jsをローカルに置きたい場合
│   │
│   ├── templates # 開発している中で増えていくが、動作確認終わったら消ししていく感じ
│   │   ├── index.html
│   │   ├── index2.html
│   │   ├── index3.html
│   │   ├── layout.html
│   │   ├── layout2.html
│   │   ├── layout3.html
│   │   ├── navbar_v1.html
│   │   ├── navbar_v2.html
│   │   └── navbar_v3.html
│   │
│   │  #開発環境では使わないけど
│   ├── uwsgi.ini
│   └── uwsgi.py
│
│   # 開発環境では使わないけど
└── web
    └── nginx.conf

1.3 venv

  • venv環境を作る
pj05_test配下でvenv作成
#プロジェクトフォルダに移動
cd pj05_test
#venv環境作成
python -m venv .venv_pj05
# .venv_pj05は適当なvenv環境名
# .をつけて、Project通番もつけてる

# activate
source .venv_pj05/bin/activate

# 必要なものをインストール
pip list # 現状確認
# 必須なもの
pip install flask
pip install --upgrade pip
pip install python-dotenv
# 以降は、必要に応じてよしなに
pip install pandas
pip install openai

1.4 フォルダと空ファイルの作成

  • 先にフォルダ作って、空ファイル作る。どこに何を置くかが明確なので
pj05_testフォルダ内で
# フォルダ作成
mkdir flaskapp
mkdir web
cd flaskapp
mkdir templates #sを忘れずに
mkdir static
# ファイル作成
touch app.py
touch views.py
touch .env
# そのまま書き込んでゆく場合
vi app.py
# この辺で素直にVisual Studio Codeを開く

1.5 .envに記述

  • .envファイルを作成して以下を記述
flaskapp/.env
#以下を記述
FLASK_APP=app.py        # <====開発環境のみ
FLASK_ENV=development   # <====開発環境のみ
# 必要に応じて
OPENAI_API_KEY = hogehogefugafuga

2.python記述

  • VS Codeを開き、記述する
  • 画面は、左にエクスプローラー、右上がコード、右下がターミナル表示にしてる

2.0 前提知識

  • 私の前提知識がないところを、ChatGPTに聞いてみたので転機しておく
    • 疑問1:なぜFlaskは、__init__.pyではなく、app.pyに記述するのか
    • 疑問2:app.pyとルーティング系views.pyに分けるメリット
  • 生成AI(ChatGPTによる回答):
    • Flaskアプリケーションの開発で __init__.py ではなく app.py を使用するのは、主にプロジェクトのシンプルさや標準的な構成によるものです。また、ルーティング処理を views.py に分離するのは、コードの保守性や拡張性を高めるためです。それぞれの理由を詳しく説明します。

2.0.1. __init__.py ではなく app.py を使う理由

2.0.1.1 プロジェクトのシンプルさ

  • 小規模なFlaskアプリケーションでは、1つのファイルにアプリケーションを記述することが一般的です
  • app.py という名前は直感的であり、どのファイルがFlaskアプリケーションのエントリーポイントなのかが一目でわかります
  • __init__.py は主に パッケージ初期化 のためのファイルとして使われるため、アプリのエントリーポイントとするのはやや直感的ではありません

2.0.1.2 エントリーポイントの明確化

  • Flaskアプリケーションを起動する際に、flask runpython -m flask で明示的にエントリーポイントを指定することがあります
  • app.py であれば、Flaskはデフォルトで app というモジュール(app.py)をエントリーポイントとして探し、アプリケーションを起動します
    flask run --app app
    
  • __init__.py にアプリを定義した場合、--app オプションでパッケージ名を指定する必要があり、やや冗長です

2.0.1.3 モジュールとパッケージの違い

  • app.py は1つのモジュールとして機能し、単純なアプリケーションのエントリーポイントに適しています
  • __init__.py はパッケージの初期化処理のために使われるため、プロジェクトが複数のモジュールから構成される大規模な場合に、Flaskアプリケーションのインスタンスをここで作成することが一般的です

2.0.2. app.pyviews.py を分離する理由

2.0.2.1 コードの責務を分離(Separation of Concerns)

  • app.pyアプリケーションの設定エントリーポイント の役割を持たせ、views.py には ルーティングやビジネスロジック を記述することで責務が明確になります
  • 例えば、app.py には以下のようにアプリケーションの設定のみを記述します
    from flask import Flask
    app = Flask(__name__)
    
    # ルーティングのインポート
    from views import *
    
    if __name__ == "__main__":
        app.run(debug=True)
    
  • views.py にはルーティング処理を記述します
    from app import app
    @app.route("/")
    def home():
        return "Hello, Flask!"
    

2.0.2.2 コードの保守性・拡張性

  • ルーティングが増えた場合、1つのファイルにすべて書くとコードが膨大になり、可読性が低下します。
  • views.py を使って分割することで、異なる機能ごとにルーティング処理をファイル単位で整理できます。例えば:
    • views.py:基本ルーティング
    • auth.py:認証関連のルーティング
    • api.py:APIエンドポイントのルーティング
  • 将来的に機能を追加・変更する際も、影響範囲が限定されるためメンテナンスが容易になります

2.0.2.3 チーム開発のしやすさ

  • 大規模なアプリでは複数人での開発が必要になることが多いです。
  • app.pyviews.pyauth.py などに分離すれば、異なる担当者が異なる部分を同時に開発できます

2.0.2.4 テストの容易さ

  • コードが分離されていることで、各部分をユニットテストしやすくなります
  • 例えば、ルーティングやビジネスロジックのテストだけを views.py に対して行うことが可能です

2.0.3 まとめ

  • app.py はFlaskアプリのエントリーポイントを明確にし、小規模なアプリケーションにはシンプルで適しています
  • __init__.py はパッケージ構成が必要な大規模なアプリで使用されます
  • ルーティングを views.py に分離することで、コードの責務が明確化され、保守性・拡張性・テストのしやすさが向上します

シンプルなアプリは app.py のみで完結できますが、開発が進むにつれてコードの分割やモジュール化が重要になってきます

2.1 app.py

  • Flaskでは、通常app.pyがアプリインスタンスを定義する場所としている
  • appモジュール(フォルダ名や同名のapp.py)を探しにいき、見つけたら
    それ(app.py)から(from)、そこに定義された appというオブジェクト
    app=Flask(__name__)ここではFlaskのアプリインスタンスをimportする
flaskapp/app.py
#アプリケーションをインポート
from flask import Flask, render_template, request, jsonify
from dotenv import load_dotenv
import openai
import os
import sys
     
# Flaskアプリケーションのインスタンス作成
app = Flask(__name__)

# 同じ階層の views.pyを最後にインポートして循環インポートを回避
import views

# .envファイルの内容を読み込む
load_dotenv()

# OpenAI APIキー (必要に応じて)
#openai.api_key = os.environ.get('OPENAI_API_KEY')

# 以下views.pyに切り出す場合は不要
# @app.route('/')
# def index():
#   return '<h2>Hello World!</h2>'
      
# Pythonスクリプトとして実行された場合、アプリケーションを実行
# 開発環境のみで必要
if __name__ == "__main__":
    app.run(host='127.0.0.1', port=5000, debug=True) #開発環境のみで必要

2.2 views.py

flaskapp/views.py
from app import app
from flask import render_template, request, jsonify, render_template_string
import openai

import generate_cy
import generate_elements_cy

# Flaskのルーティング
# 初手としてまずは動くか確認
@app.route('/')
def index():
    # step1
    return "<h1>Hellow World!</h1>"
    # step2
    #data = 'views.pyのinsert_something部分です'
    #return render_template("index.html", insert_something=data)
    # step3
    #my_dict_data = {
    #         'key1' : 'value1',
    #         'key2' : 'value2',
    #         'titles': [ 'title_name1', 'title_name2', 'title_name3']
    #         }
    #return render_template('index.html', my_dict=my_dict_data)

# index以外のページを作って動作確認
@app.route('/test')
def other1():
    return render_template('index2.html')

# layout.htmを使ったページでの動作確認
@app.route('/test3')
def test3():
    return render_template('index3.html')

# csvデータを読み込んで表示するページ
@app.route('/table')
def table():
    return render_template('dammy_table.html')

# pythonで吐き出したHTMLファイルをそのまま出す場合
@app.route('/graph')
def graph():
    return render_template('graph.html')


# jinja2等で生成したファイルをそのまま表示させる場合
# render_template_stringを使う。さくっと見たい場合
@app.route("/cy")
def network_graph():
    html_content = generate_cy.generate_html()
    return render_template_string(html_content)

# pythonでelements部分を作り、レイアウトに埋め込む場合
@app.route("/elements_cy")
def cytoscape_graph():
    elements = generate_elements_cy.generate_elements()
    return render_template("network_graph_layout.html", elements=elements)

2.3 その他Pythonファイル

  • 必要に応じて適宜作成
  • 共通して言えそうなところ
  1. returnとしてHTMLファイルに埋め込んで返す場合
  • ポイントは作成したPythonファイル名が generate_cy.pyとしたとき、views.pyには、from generate_cyと読み込む行を忘れずに入れる
  • 作成したpythonファイルの返り値がHTMLファイルでそのまま使える場合は、views.pyでは、return render_template_string(html_content)として入れる
flaskapp/generate_cy.py
# 例1 HTMLファイルを返す場合
import pandas as pd
import networkx as nx
import json

def generate_html():
    # CSVファイルを読み込み
    df = pd.read_csv("./static/csvdata/dammy_data.csv")

    # NetworkXのグラフを作成
    G = nx.Graph()

  # 中間コード省略

   # HTMLの生成
   html_content="""
   <!DOCTYPE html>
   <html lang="en">
   <head>
      <meta charset="UTF-8">
      <title>TITLE NAME</title>
      <link href="./static/css/xxx.css" rel="stylesheet" type="text/css" />
      <script src="./static/js/xxx.js"></script>
      <style>
            #cy {{
                width: 900px;
                height: 400px;
                border: 1px solid black;
            }}
     </style>
     </head>
     <body>
        <h2>Network Graph</h2>
        <div id="cy"></div>
        <hr>

        <script>
        <!-- 中略 -->
        </script>
    </body>
    </html>
    """
    return html_content
flaskapp/views.py
from app import app
from flask import render_template, request, jsonify, render_template_string

import generate_cy #<--追加

@app.route('/')
def index():
   hogefuga

# jinja2等で生成したファイルをそのまま表示させる場合
# render_template_stringを使う。さくっと見たい場合
@app.route("/cy")
def network_graph():
    html_content = generate_cy.generate_html()
    return render_template_string(html_content)

2.HTMLファイル内の要素をreturnとして返す場合

  • 作成したpythonファイルの返り値が、HTMLファイルを構成する要素(elements)だった場合は、それを埋め込むlayout系のHTMLファイルを用意し、views.pyには、return render_template("出力HTML名.html", elements=elements)とする
flaskapp/generate_elements_cy.py
# 例2 elementsを返す場合
import pandas as pd
import networkx as nx
import json

def generate_elements():
    # csvファイルを読み込んでDFにする
    df = pd.read_csv("./static/csvdata/dammy_data.csv")

    # NetworkXのグラフを作成
    G = nx.Graph()
    
    #中間の処理は省略

    return elements
flaskapp/templates/network_graph_layout.html
<!doctype html>
<html lang="en">
<head>
<!--中略-->
</head>
<body>
    <h2>Network Graph</h2>
    <div id="cy"></div>
    <script>
        var cy = cytoscape({
            container: document.getElementById('cy'),
            elements: {{ elements|tojson }},
            style: [
                {
        //中略
    </script>
</body>
</html>
flaskapp/views.py
from app import app
from flask import render_template, request, jsonify, render_template_string

import generate_cy
import generate_elements_cy #<--忘れずに

# 中略

# pythonでelements部分を作り、レイアウトに埋め込む場合
@app.route("/elements_cy")
def cytoscape_graph():
    elements = generate_elements_cy.generate_elements()
    return render_template("network_graph_layout.html", elements=elements)

render_templateと render_template_stringどちらを使うべきか?

  • render_template:
    • 再利用性が高い
    • テンプレートファイルがコードと分離されているため、保守性が向上
    • 複雑なアプリケーションやプロダクション環境に最適
  • render_template_string:
    • 簡単なプロトタイプやデバッグ用途に適している
    • HTMLテンプレートを外部ファイルとして管理したくない場合に便利
  • 結論
    • プロジェクトの規模や要件に応じて選択
    • 長期的には、再利用性や保守性を考慮するとrender_templateに軍配

3.HTMLファイル記述

3.1 index.html

templates/index.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>テストWebアプリ</title>
</head>
<body>
    <h1>index.html表示してます</h1>
    <!-- step2  step2実行時は、step3は消しておく.コメントアウトはできない Internal Server Error-->
    {{ insert_something }}

    <!-- step3 -- step3実行時は Step2は、消して置かないとエラーになる-->
    <p>{{ my_dict.key1 }}</p>
    <p>{{ my_dict.key2 }}</p>

    <!-- /test (index2.html)へのルーティング def other1():の other1を指定している -->
    <!-- views.pyでのルーティング設定、index2.htmlのファイルがない場合エラー -->
    <a href="{{ url_for('other1') }}">test</a>に移動する<br>

    <!-- /test3 (index3.html)へのルーティング def test3():の test3を指定している ---->
    <!-- views.pyでのルーティング設定、index3.htmlのファイルがない場合エラー -->
    <a href="{{ url_for('test3') }}">test3</a>に移動する<br>
</body>
</html>%                    
templates/index2.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>テストWebアプリ2</title>
</head>
<body>
    <h1>index2.html表示してます</h1>
</body>
</html>
index3.html
<!-- layout ~ layout3 は適宜選ぶ -->
{% extends "layout.html" %}

{% block content %}
<h1>index3.html表示してます</h1>
<h2>タイトル表示</h2>
<p>このページはlayout.htmlを利用しています</p>

{% endblock %}
suzukita@szkMac templates % 

3.2 layout.html

  • シンプルにlayoutを使った動作確認用
templates/layout.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>sample flask app</title>
</head>
<body>
{% block content %}{% endblock %}
</body>
</html>
  • BootstrapのNavbarだけ使った場合
templates/layout2.html
<!DOCTYPE html>
<html lang="ja">
<head>
	<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">

  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
  <link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}"/>

	<title> This is TEST WEB site</title>
</head>
<body>
    <nav class="navbar navbar-expand-lg navbar-light" style="background-color: #e3f2fd;">
        <div class="container-fluid">
          <a class="navbar-brand" href="#">Navbar</a>
          <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
            <span class="navbar-toggler-icon"></span>
          </button>
          <div class="collapse navbar-collapse" id="navbarNavAltMarkup">
            <div class="navbar-nav">
              <a class="nav-link active" aria-current="page" href="#">Home</a>
              <a class="nav-link" href="#">Features</a>
              <a class="nav-link" href="#">Pricing</a>
              <a class="nav-link disabled" href="#" tabindex="-1" aria-disabled="true">Disabled</a>
            </div>
          </div>
        </div>
      </nav>
    {% block content %}
    {% endblock %}
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>

</body>
</html>
  • DashboardをBootStrapで作り込みたいとき
  • Navbarだけは、別ファイルにした場合
flaskapp/templates/layout3.html
<!doctype html>
<html lang="ja">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Bootstrap Sample</title>

    <!-- BootstrapのCDNでのCSS読み込み -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" 
          rel="stylesheet" 
          integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" 
          crossorigin="anonymous"
    >

    <!-- sidebar CSS --->
    <style>
        sidebar {
            position: fixed;
            top: 0;
            bottom: 0;
            left: 0;
            z-index: 100;
            padding: 90px 0 0;
            box-shadow: inset -1px 0 0 rgba(0, 0, 0, .1);
            z-index: 99;
        }

        @media (max-width: 767.98px) {
        .sidebar {
            top: 11.5rem;
            padding: 0;
        }
        }

        .navbar {
        box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .1);
        }

        @media (min-width: 767.98px) {
        .navbar {
            top: 0;
            position: sticky;
            z-index: 999;
        }
        }

        .sidebar .nav-link {
        color: #333;
        }

        .sidebar .nav-link.active {
        color: #0d6efd;
        }
    </style>

</head>

<body>
    <!--NavBarの設定-->
    <!--includeで別ファイルに記述したテンプレートを読み込める-->
    {% include "navbar_v2.html" %}


    <!--Containerの設定-->
    <div class="container-fluid">
        <div class="row">
            <!-- sidebar content -->
            <nav id="sidebar" class="col-md-3 col-lg-2 d-md-block bg-light sidebar collapse">
                <!-- sidebar content goes in here -->
                <div class="position-sticky pt-md-5">
                    <ul class="nav flex-column">
                        <li class="nav-item">
                          <a class="nav-link active" aria-current="page" href="#">
                            <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-home"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"></path><polyline points="9 22 9 12 15 12 15 22"></polyline></svg>
                            <span class="ml-2">Home</span>
                          </a>
                        </li>
                        <li class="nav-item">
                          <a class="nav-link" href="#">
                            <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-file"><path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"></path><polyline points="13 2 13 9 20 9"></polyline></svg>
                            <span class="ml-2">Overview</span>
                          </a>
                        </li>
                        <li class="nav-item">
                          <a class="nav-link" href="#">
                            <i class="bi bi-database"></i>
                            <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-database" viewBox="0 0 16 16">
                               <path d="M4.318 2.687C5.234 2.271 6.536 2 8 2s2.766.27 3.682.687C12.644 3.125 13 3.627 13 4c0 .374-.356.875-1.318 1.313C10.766 5.729 9.464 6 8 6s-2.766-.27-3.682-.687C3.356 4.875 3 4.373 3 4c0-.374.356-.875 1.318-1.313M13 5.698V7c0 .374-.356.875-1.318 1.313C10.766 8.729 9.464 9 8 9s-2.766-.27-3.682-.687C3.356 7.875 3 7.373 3 7V5.698c.271.202.58.378.904.525C4.978 6.711 6.427 7 8 7s3.022-.289 4.096-.777A5 5 0 0 0 13 5.698M14 4c0-1.007-.875-1.755-1.904-2.223C11.022 1.289 9.573 1 8 1s-3.022.289-4.096.777C2.875 2.245 2 2.993 2 4v9c0 1.007.875 1.755 1.904 2.223C4.978 15.71 6.427 16 8 16s3.022-.289 4.096-.777C13.125 14.755 14 14.007 14 13zm-1 4.698V10c0 .374-.356.875-1.318 1.313C10.766 11.729 9.464 12 8 12s-2.766-.27-3.682-.687C3.356 10.875 3 10.373 3 10V8.698c.271.202.58.378.904.525C4.978 9.71 6.427 10 8 10s3.022-.289 4.096-.777A5 5 0 0 0 13 8.698m0 3V13c0 .374-.356.875-1.318 1.313C10.766 14.729 9.464 15 8 15s-2.766-.27-3.682-.687C3.356 13.875 3 13.373 3 13v-1.302c.271.202.58.378.904.525C4.978 12.71 6.427 13 8 13s3.022-.289 4.096-.777c.324-.147.633-.323.904-.525"/>
                            </svg>
                            <span class="ml-2">DataTable</span>
                          </a>
                        </li>

                        <li class="nav-item">
                          <a class="nav-link" href="#">
                            <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-bar-chart-2"><line x1="18" y1="20" x2="18" y2="10"></line><line x1="12" y1="20" x2="12" y2="4"></line><line x1="6" y1="20" x2="6" y2="14"></line></svg>
                            <span class="ml-2">Reports</span>
                          </a>
                        </li>

                      </ul>
                  </div>
                    
            </nav>

            <!-- main content -->
            <main class="col-md-9 ml-sm-auto col-lg-10 px-md-4 py-4">
                <!--パンくずリスト-->
                <nav aria-label="breadcrumb">
                    <ol class="breadcrumb">
                      <li class="breadcrumb-item"><a href="#">Home</a></li>
                      <li class="breadcrumb-item active" aria-current="page">Overview</li>
                    </ol>
                </nav>
                <h1 class="h2">Overview</h1>
                <p>This is the homepage of a simple admin interface which is part of a tutorial written on Themesberg</p>
                    

                <!--main content start-->
                {% block content %}{% endblock %}
                <!--main content end -->

                
                <!-- Footer は mainタグの終わりの前にいれる-->
                <footer class="pt-5 d-flex justify-content-between">
                    <span>Copyright © 2024-2025 <a href="">CORPORATION NAME</a></span>
                </footer>
                <!--Footerはmainタグが終わる前にいれる。ここまで-->
            </main>
        </div>
    </div>


    <!-- BootstrapのCDNでのjs読み込み -->
    <!--Bundle type: bootstrapに、popperをバンドルした一体型-->
    <script 
        src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"
        integrity="sha384-geWF76RCwLtnZ8qwWowPQNguL3RmwHVBC9FhGdlKrxdiJJigb/j/68SIy3Te4Bkz"
        crossorigin="anonymous"
    ></script>
    <!--Popperとbootstrap JSを別々も可能。ドロップダウン、ポップオーバー、ツールチップを使う予定がない場合は、Popperを含めないことで何キロバイトか節約することができる-->
    <!-- 分離型
    <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.8/dist/umd/popper.min.js" integrity="sha384-I7E8VVD/ismYTF4hNIPjVp/Zjvgyol6VFvRkX/vR+Vc4jQkC+hVqc2pM8ODewa9r" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.min.js" integrity="sha384-fbbOQedDUMZZ5KreZpsbe1LCZPVmfTnH7ois6mU1QK+m14rQ1l2bGBq41eYeM/fS" crossorigin="anonymous"></script>
    -->
</body>
</html>

Bootstrapのアイコンを変えたい場合は以下から選ぶ

3.3 Navbar

flaskapp/templates/navbar_v2.html
<!--NavBarの設定-->
<nav class="navbar navbar-expand-lg bg-body-tertiary">
    <div class="container-fluid">
        <a class="navbar-brand" href="#">Navbar</a>
        <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
            <span class="navbar-toggler-icon"></span>
        </button>
        <div class="collapse navbar-collapse" id="navbarNav">
        <ul class="navbar-nav">
        <li class="nav-item">
            <a class="nav-link active" aria-current="page" href="#">Home</a>
        </li>
        <li class="nav-item">
            <a class="nav-link" href="#">Features</a>
        </li>
        <li class="nav-item">
            <a class="nav-link" href="#">Pricing</a>
        </li>
        <li class="nav-item">
            <a class="nav-link disabled">Disabled</a>
        </li>
        </ul>
      </div>
    </div>
</nav> 

4.static系のものを揃える

4.1 css

  • 必要なCSSを入れる
flaskapp/static/css/style.css
h1 {
    color: blue;
    border-bottom: double 6px #87CEFA;
}

4.2 js

  • jsに適当なjavascriptを入れる
flaskapp/satic/js/sample.js
window.onload = function() {
    var changeColor = function() {
        var e = document.getElementById('test');
        e.style.color = 'red';
        console.log("書き換えテスト")
    }
    setTimeout(changeColor, 5000);
}                   

4.3 iamges

  • imagesに適当な画像を入れる
flaskapp/static/images/sample.png
static
 │
 └── images
       │
       └──  sample.png

5.flaskを起動して確認

  • flaskを起動する。開発中モードなので、起動時にWSGIを使ってねと警告がされるが、http://127.0.0.1:5000をcmd+クリックでブラウザ表示して確認する
  • 確認が終了したら,CTRL+Cで止める
pj05_test/flaskapp
(.venv_pj05) username@Macbook flaskapp % flask run
 * Serving Flask app 'app.py'
 * Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on http://127.0.0.1:5000
Press CTRL+C to quit

6.参考リンク

Qiita 初心者プログラマーのWebアプリ

【Docker】Nginx+uWSGI+Flaskのコンテナ構築

Flask Documentationの日本語訳

Bootstrap getting-started

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?