概要
今回はPythonの「Flask」を用いてWebアプリケーションを構築してみようと思います。
構築に使用したサービス
実行環境:Windows11 - WSL(Ubuntu 24.04 LTS)
エディター:Visual Studio Code
バックエンド:Python + Flask(フレームワーク)
フロントエンド:HTML + jinja2
ミドルウェア:SQLite3(データベース)
結果
Flaskフレームワークとjinja2パッケージを組み合わせることで、ブラウザ(html)にデータベースのデータを表示したり、ブラウザから入力したデータをPythonを通してデータベースに登録することができました。また、1つ1つのコードを分析し、システムが処理する順番を知ることで、バックエンドがフロントエンドとミドルウェアの仲介をしているということを理解できました。
各サービスの関係性を簡単に図に表すと下記のようになると思います。
ファイル構成
~/Python_Web_Project/ (プロジェクトのルート)
├── flaskr/
│ ├── __init__.py
│ ├── main.py
│ ├── db.py
│ └── templates/
│ ├── index.html
│ ├── form.html
└── nix-shellのファイルなど
手順①:WSL2のセットアップ
WSL2とは:Windows Subsystem for Linux 2 の略称で,Windows上で Linux を仮想的に動かすことができるシステム環境のことです。
I. コマンドプロンプト(cmd)を開き、下記のコマンドを入力します。
wsl --install
II. Ubuntuのインストールが始まります。インストールが完了したら「user account(ユーザー名)」と「New password(パスワード)」を入力します。
問題なければ入力したユーザー名とUbuntuのCLIが表示されます。

III. 次にVS Codeを開き、拡張機能からWSLをインストールします。これでVS CodeからUbuntu内のファイルを直接編集できるようになります。

IV. VS Codeの左下にある「><」アイコンをクリックし、「WSL」と入力するとメニューに「WSLへの接続」が表示されるので選択します。画面左下に青色で「WSL: Ubuntu」と表示されれば接続完了です。


初期化するには(失敗した人用)
I. コマンドプロンプト(cmd)を開き、下記のコマンドを入力してインストールされているLinuxを確認します。
wsl --list
II. 確認したシステム名を指定して下記のコマンドを入力します。
wsl --unregister <システム名>
# 例:wsl --unregister Ubuntu
手順②:Nixのインストール
Nixとは:Linuxで使えるパッケージ管理システムです。プロジェクトごとに必要なツールを隔離して管理できるため、バージョン管理が楽になります。今回はpythonパッケージの「flask」をインストールします。
I. VS code「表示>ターミナル」を開き、下記のコマンドを実行してNix (パッケージマネージャ)をインストールします。途中で「Proceed?」と聞かれるので"Y"と入力します。「Nix was installed successfully!」と表示がされれば、インストール完了です。
curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install
上記コマンドの分解解説
| パーツ | 役割 |
|---|---|
| curl | "Client URL"の略。URLを扱うためのクライアントソフト。データを転送するためのツールです。ここではインターネットからファイルを落とす役割です。 |
| --proto '=https' --tlsv1.2 | 通信の「安全なルール(プロトコル)」を指定。HTTPSと特定の暗号化規格(TLS 1.2)を使うという指示です。 |
| -sSf -L | curlのオプション。「静かに、エラーがあれば即中止し、リンク先が移動していても追いかける」という設定です。 |
| https://.../nix | Nixのインストールスクリプト本体が置いてあるURL。 |
| | | パイプ。curlで受け取ったデータを次のコマンド(sh)へ橋渡しします。 |
| sh -s -- install | 受け取ったデータを「シェル(命令実行機)」で実行し、さらに「install」という指示を与えます。 |
-sSf -Lオプションの説明
| オプション | 意味 |
|---|---|
| -s(Silent) | 進捗状況のメーターやエラーメッセージを非表示にします。処理中に余計な文字が画面に出ないようにするために使います。 |
| -S(show-error) | -s(silent)を指定していても、もし通信に失敗した時だけはエラーメッセージを表示させます。 |
| -f(fail) | HTTPエラー(404 Not Foundなど)が発生した際、終了コードを「失敗」として返します。エラー後のスクリプトの誤作動を防げます。 |
| -L(location) | 指定したURLが「転送(リダイレクト)」されていた場合、自動的に転送先のURLへアクセスします。(例: 古いURL(/old-page)にアクセスしようとすると、新しいURL(/new-page)に飛ばします。 |
sh -s -- installコマンドの説明
| パーツ | 役割 |
|---|---|
| sh | シェル(コマンド実行プログラム)を起動します。 |
| -s(standard input) | コマンドをファイルからではなく、「標準入力(パイプなどで流れてきた文字)」から読み込むオプション。 |
| -- | 「オプションの終わり」を意味する記号。これ以降の文字はshコマンドへの命令ではなく、実行されるスクリプト(nix)への引数として扱われます。 |
| install | 実行されるスクリプト(nix)を「インストールモード」に設定する引数(パラメータ)。 |
II. 続けてターミナルに下記のコマンドを入力してフォルダを作成し、フォルダの場所に移動します。
mkdir Python-Web-Project
cd Python-Web-Project
III. 下記のコマンドを入力し、作成したフォルダをVS codeの新しいウィンドウとして開きます。
code .
IV. Python-Web-Projectフォルダの中に「flake.nix」を作成し、下記のコードを追加します。
{
description = "Python Webapp Environment";
# ツール(フレームワーク)の仕入れ先
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
};
outputs = { self, nixpkgs }:
let
# システムの定義
system = "x86_64-linux";
pkgs = import nixpkgs {
inherit system;
config.allowUnfree = true; # 一部オープンソースではない(ライセンス制限がある)ツールの使用を許可
};
in
{
devShells.${system}.default = pkgs.mkShell {
# 追加するツール(フレームワーク)の種類
buildInputs = with pkgs; [
(python3.withPackages (ps: with ps; [
flask
]))
];
# 環境変数の設定
shellHook = ''
export FLASK_APP=flaskr
export FLASK_ENV=development
'';
};
};
}
V. ターミナルに下記のコマンドを入力してNix環境をインストールします。成功すればflake.lockファイルが作成され、ユーザー名の左側には(nix:nix-shell-env)と追加されます。
nix develop --impure
初期化するには(失敗した人用)
I. ターミナルを開き、下記のコマンドを入力するとNix環境をクリアにできます。
nix-collect-garbage -d
rm -f flake.lock
II. Nix自体を完全にアンインストールする場合は、下記のコマンドを入力します。
sudo systemctl stop nix-daemon.service
sudo systemctl disable nix-daemon.service
sudo rm /etc/nix/nix.conf
sudo rm /etc/profile.d/nix.sh
sudo rm -rf /nix
おまけ:ファイル構成を別にする場合
今回のファイル構成では、「Python_Web_Project」フォルダをルートフォルダとし、手順③で作成する「flaskr」フォルダにシステムファイルを構築していきます。
もし「Python_Web_Project」フォルダ内にシステムファイルを構築したい場合は、flake.nixの環境変数を下記に変更します。
# 環境変数の設定
shellHook = ''
export FLASK_APP=.
export FLASK_ENV=development
'';
※他ファイルで「flaskr」を指定したところも同じように「.」に変更する必要があります。
手順③:__init__.pyの作成
開発環境が整ったので、早速Webアプリを構築していきます。ターミナルに下記のコマンドを入力してフォルダを作成し、フォルダの場所に移動します。
mkdir flaskr
cd flaskr
その後、「flaskr」フォルダ内に「__init__.py」を作成し、下記のコードを入力します。
from flask import Flask # flaskモジュールのFlaskクラスをインポート
app = Flask(__name__) # flaskを実行する場所をこのファイルに指定
import flaskr.main # flaskrパッケージ内のmainモジュールをインポート
from flaskr import db # flaskrパッケージ内のdbモジュールをインポート
db.create_books_table() # 後のdb.pyで定義する関数
「flask」とは
flaskとは:Webアプリケーションフレームワークのうちの1つです。個人的には「バックエンド(サーバーサイド)」やルーティングとして使用している感じでした。
「__init__.py」について
__init__.pyとは:__init__.pyはpythonの中でも特殊なファイルです。これがあると、そのディレクトリをパッケージとして扱うことができます。また、import文を使って同じディレクトリのファイルをモジュールとして呼び出すことができます。
【app=Flask(__name__)】について
| パーツ | 役割 |
|---|---|
| (__name__) | (__name_)は自動的に定義される変数で、現在のファイルのモジュール名が入ります。Pythonのモジュールの実体は、「.py」の拡張子を持つプログラムファイルです。つまり、現在のファイル名(__init__.py)に変換されます。 |
| Flask(__name__) | 上記を踏まえたうえで、Flask(__name__)は、「flaskに"__init__.pyが今回のアプリの本体である"ことを知らせる」ための関数であると個人的に認識しています。 |
| app = Flask(__name__) | appという変数に代入することで、他ファイルのルーティングを手助けすることができます。 |
【import flaskr.mainとfrom flaskr import db】について
| パーツ | 役割 |
|---|---|
| import flaskr.main | 「手順④」で説明するflaskrフォルダ(パッケージ)内のmain.pyを読み込むコードです。今回の場合「app」で記述したURLのルーティング情報を読み込みます。 |
| from flaskr import db | 「手順⑤」で説明するflaskrフォルダ(パッケージ)内のdb.pyを読み込むコードです。呼び出した後は db.create_books_table() のようにファイル内の関数を実行できます。 |
| 「import A.B」と「from A import B」の違い | どちらもモジュールやパッケージを読み込むための構文ですが、「import A.B」は都度「A.B.関数名()」のようにフルネーム(修飾付き)で書く必要があるため、その関数やクラスが「どこのパッケージのものか」がコード上で一目で分かります。「from A import B」は「B.関数名()」のみ書くことができるため、コードが短くなり読みやすくなります。 |
手順④:main.pyの作成
「flaskr」フォルダ内に「main.py」を作成し、下記のコードを入力します。
from flaskr import app
from flask import render_template, request, redirect, url_for
import sqlite3
DATABASE = 'database.db'
@app.route('/') # @(デコレータ)でルーティングを設定
def index():
con = sqlite3.connect(DATABASE)
db_books = con.execute('SELECT * FROM books').fetchall()
con.close()
# htmlに渡す辞書型オブジェクトに変換
books = []
for row in db_books:
books.append({'title': row[0], 'price': row[1], 'arrival_day': row[2]})
# 初期ページとして'index.html'を設定
return render_template(
'index.html',
books=books
)
@app.route('/form') # htmlから受け取るURLが'/form'の場合に関数を実行
def form():
return render_template(
'form.html'
)
# htmlから受け取るURLが'/register'且つ'POSTリクエスト'の場合に関数を実行
@app.route('/register', methods=['POST'])
def register():
# formタグから受け取ったデータを変数に代入
title = request.form['title']
price = request.form['price']
arrival_day = request.form['arrival_day']
con = sqlite3.connect(DATABASE)
con.execute('INSERT INTO books VALUES(?, ?, ?)', [title, price, arrival_day]) # データをbooksテーブルに登録
con.commit() # データベースへ変更を反映
con.close()
return redirect(url_for('index'))
上記コードのポイント
| 項目 | 詳細 |
|---|---|
| DATABASE = 'database.db' |
database.dbを変数「DATABASE」に代入しています。こうすることで、database.dbのファイル名や保存場所が変わった場合、この変数を変更するだけで「DATABASE」を参照している部分全てを更新することができる。 |
| @(デコレータ)とは | Python版のルーティング機能だと思ってます。「@(モジュール).route(URL)」と記入し、該当するURLをモジュールから受け取った場合に、次の行で定義した関数を実行します。 |
| execute('')とexecute("")の違い | SQL文を実行する関数ですが、どちらでも問題ないらしいです。ただし、SQL文の中で 'J-POP' や '2026-05-17' のように特定の文字を囲むためにシングルクォーテーション(')を使うと分かりやすいです。 |
| render_templateとは | jinja2テンプレートエンジンを使用するための関数です。python側にアクセスするhtmlファイルと変数を記入し、html側に二重の波括弧( {{}} )でデータを囲むことで、対象のデータをhtmlに表示させることができます。 ※テンプレートエンジンとは、HTMLのテンプレートに、バックエンドなどでやりとりしたロジックやデータを表示するためのソースコードを埋め込み、合体させるものらしいです。 |
| request.form[] | htmlで入力されたデータを取得するための関数です。具体的にはform.htmlのfromタグから「/register」へ送られてきたデータを受け取ります。 |
【con.execute('SELECT * FROM books').fetchall()】について
| 項目 | 詳細 |
|---|---|
| execute() | ()内のSQL文を実行する関数です。SQL文はクオーテーションマーク('')もしくはダブルクオーテーションマーク("")で囲む必要があります。 |
| SELECT * FROM books | booksテーブルからすべてのデータ(*)を読み込むコードです。 |
| fetchall() | booksテーブルから読み込んだデータを「リストオブジェクト」に変換します。リストオブジェクトとは、要素と呼ばれるデータの列を角括弧([])で保持するために使用されます。ちなみに、この時のデータの形は、[(データ1-1, データ1-2, データ1-3),(データ2-1, データ2-2, データ2-3)...]のようになります。 |
【con.execute('INSERT INTO books VALUES(?, ?, ?)', [title, price, arrival_day])】について
| 項目 | 詳細 |
|---|---|
| execute() | ()内のSQL文を実行する関数です。SQL文はクオーテーションマーク('')もしくはダブルクオーテーションマーク("")で囲む必要があります。 |
| 'INSERT INTO books VALUES(?, ?, ?)', [title, price, arrival_day] | booksテーブルにVALUES()の値を追加するコードです。(?)と書かれているのはプレースホルダと呼び、[title, price, arrival_day]の値を当てはめます。(?)を削除して直接値を追加することもできますが、このような2段構成にすることで、SQL文にかかわるような「特殊文字」を無効化し、SQLインジェクションを回避することができます。 |
手順⑤:db.pyの作成
「flaskr」フォルダ内に「db.py」を作成し、下記のコードを入力します。データベースはPythonの標準ライブラリである「SQLite3」を使用します。
import sqlite3
DATABASE = 'database.db' # データベースを変数に代入
def create_books_table():
# 変数「DATABASE」にアクセスし、「con(コネクション)」オブジェクトに代入
# ファイル(database.db)がなければ新規で作成
con = sqlite3.connect(DATABASE)
# booksテーブルを作成
# 「IF NOT EXISTS」を入れることで、テーブルが既にあってもエラーを回避
con.execute("CREATE TABLE IF NOT EXISTS books (title, price, arrival_day)")
# データベースとの接続を切ります
# 他のプロセスがデータベースと接続できなくなるため必須
con.close()
手順⑥:index.htmlの作成
「flaskr」フォルダ内に「templates」フォルダを作成します。その中に「index.html」を作成し、下記のコードを入力します。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>Python_Web_Project</title>
</head>
<body>
<h1>MRT書店</h1>
<h2>今月の新刊一覧</h2>
{% if books == [] %}
<p>今月の新刊情報はまだありません</p>
{% else %}
<!-- 表の作成、borderは線の太さを示す -->
<table border="1">
<tr>
<th>入荷日</th>
<th>タイトル</th>
<th>金額</th>
</tr>
{% for book in books %}
<tr>
<td>{{ book.arrival_day }}</td>
<td>{{ book.title }}</td>
<td>{{ book.price }}円</td>
</tr>
{% endfor %}
</table>
{% endif %}
<a href="{{ url_for('form') }}">編集</a>
</body>
</html>
手順⑦:form.htmlの作成
「templates」フォルダ内に「form.html」を作成し、下記のコードを入力します。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>Python_Web_Project</title>
</head>
<body>
<h1>MRT書店</h1>
<!-- formタグを使ってデータの登録機能を表示 -->
<form method="post" action="{{ url_for('register')}}">
<table border="1">
<tr>
<th>入荷日</th>
<th>タイトル</th>
<th>金額</th>
</tr>
<tr>
<td><input type="text" name="arrival_day"></td>
<td><input type="text" name="title"></td>
<td><input type="text" name="price"></td>
</tr>
</table>
<br>
<input type="submit" value="登録">
</form>
</body>
</html>
手順⑧:flaskの起動
I. ターミナルに下記のコマンドを入力し、「Python_Web_Project」内でflaskを立ち上げます。正常に起動ができれば「Running on http://127.0.0.1:5000」と表示されます。
cd ..
flask run
II. ブラウザに「http://127.0.0.1:5000」と入力し、「MRT書店」とタイトルが表示されればWebアプリの構築は完了です。

III. 『編集』をクリックするとテーブルが表示されるので、各項目「入荷日」「タイトル」「金額」を入力し、『登録』ボタンを選択します。

IV. 「MRT書店」タイトルページへ自動的に戻ります。入力したデータが表示されていれば、データの追加が完了となります。

参考URL





