手持ちの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に分けるメリット
- 疑問1:なぜFlaskは、
- 生成AI(ChatGPTによる回答):
- Flaskアプリケーションの開発で
__init__.py
ではなくapp.py
を使用するのは、主にプロジェクトのシンプルさや標準的な構成によるものです。また、ルーティング処理をviews.py
に分離するのは、コードの保守性や拡張性を高めるためです。それぞれの理由を詳しく説明します。
- Flaskアプリケーションの開発で
2.0.1. __init__.py
ではなく app.py
を使う理由
2.0.1.1 プロジェクトのシンプルさ
- 小規模なFlaskアプリケーションでは、1つのファイルにアプリケーションを記述することが一般的です
-
app.py
という名前は直感的であり、どのファイルがFlaskアプリケーションのエントリーポイントなのかが一目でわかります -
__init__.py
は主に パッケージ初期化 のためのファイルとして使われるため、アプリのエントリーポイントとするのはやや直感的ではありません
2.0.1.2 エントリーポイントの明確化
- Flaskアプリケーションを起動する際に、
flask run
やpython -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.py
と views.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.py
、views.py
、auth.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ファイル
- 必要に応じて適宜作成
- 共通して言えそうなところ
- 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