5. WebでのリクエストURLによる処理の振り分け(PythonのFlaskを使用)
【概要】
この演習では,Webサーバとデータベースの連携を扱う。データベースは,前回の授業で扱った MySQL Employees Sample Database を SQLite 形式に変換したものを使用する。Webサーバの構築には Python の Flask を使用する。受信した URL に応じて処理を振り分けるルーティングを通して,同一の Webサーバが URL ごとに異なる結果を返す仕組みを学ぶ。
本演習は,Flask が起動した Webサーバにブラウザからアクセスする形式のため,Windows 上の Python での実行を前提とする。Colab では別途トンネリング(外部からアクセスできるよう通信経路を中継する設定。ngrok など)が必要であり,本演習の対象外とする。
【目次】
- 1. Webサーバ
- 2. Webサーバのポート番号
- 3. リクエストのルーティング
- 4. SQLite3 でのテーブル一覧取得
- 5. 演習準備
- 6. Employees Sample データベース(SQLite版)について
- 7. 演習1.Employees Sample データベースのダウンロード
- 8. 演習2.単一URLに対する応答
- 9. 演習3.戻り値の変更
- 10. 演習4.データベースのテーブル一覧の表示
- 11. 演習5.URLによる処理の振り分け
【関連する外部ページ】
【サイト内の関連ページ】
1. Webサーバ
Webサーバは,Webブラウザ等からの要求(リクエスト)に対して返答を返す。返答は HTML やその他のオブジェクトである。
2. Webサーバのポート番号
Webサーバの起動時には,通信に使うポート番号を指定する。この演習ではポート番号 8080 を使用する。
3. リクエストのルーティング
ルーティングとは,受信した URL に応じて実行する処理を切り替える仕組みである。例えば,Webブラウザで http://localhost:8080/db にアクセスしたときは「welcome」を,http://localhost:8080/db/hoge にアクセスしたときは「hoge」を表示する動作を,次のプログラムで実現できる。
from flask import Flask
app = Flask(__name__)
@app.route('/db')
def tables():
return 'welcome'
@app.route('/db/hoge')
def hoge():
return 'hoge'
app.run(host='localhost', port=8080, debug=True)
@app.route('...') は,直後の関数を指定 URL の処理に割り当てるデコレータ(関数の動作を変更・拡張する記法)である。
4. SQLite3 でのテーブル一覧取得
SQLite3 でテーブル一覧を取得する SQL 文は次のとおりである。sqlite_master は,データベース内のテーブルやビューの定義を保持する SQLite 内部のテーブルである。
SELECT name FROM sqlite_master WHERE type='table';
5. 演習準備
この演習では Python を使用する。Python がインストールされていない場合は,下記の「Python 3.12 のインストール」を展開し,手順に従いインストールすること。続いて,下記の「必要なライブラリのインストール」を実施すること。
Python 3.12 のインストール
Pythonのインストールを行い、Pythonのプログラムを実行する環境を整える。扱う環境は、Windows搭載パソコンである。金子研究室では、Python 3.12.10を推奨する。
[Windows での Python 3.12 のインストール手順を見るには、ここをクリック]
Windows での Python 3.12 のインストール
以下のいずれかの方法でPython 3.12をインストールする。Pythonがインストール済みの場合、この手順は不要である。
方法 1:winget によるインストール
【インストールコマンドの実行方法】
管理者権限でコマンドプロンプトを起動する(手順:Windowsキーまたはスタートメニュー → cmd と入力 → 右クリック → 「管理者として実行」)。そして、コマンド全体をコマンドプロンプトにコピー&ペーストする。
--scope machine を指定することで、システム全体(全ユーザー向け)にインストールされる。このオプションの実行には管理者権限が必要である。インストール完了後、コマンドプロンプトを再起動するとPATHが反映される。
REM Python 3.12 をシステム領域にインストール
winget install --id Python.Python.3.12 -e --scope machine --silent --accept-source-agreements --accept-package-agreements --override "/quiet InstallAllUsers=1 PrependPath=1 Include_test=0 Include_pip=1 Include_launcher=1 InstallLauncherAllUsers=1 TargetDir=\"C:\Program Files\Python312\""
REM Python と Scripts を PATH 先頭に追加
powershell -NoProfile -Command "$p='C:\Program Files\Python312'; $s=\"$p\Scripts\"; $c=[Environment]::GetEnvironmentVariable('Path','Machine'); if((Test-Path $p) -and (';'+$c+';' -notlike \"*;$p;*\") -and (';'+$c+';' -notlike \"*;$s;*\")){[Environment]::SetEnvironmentVariable('Path',\"$p;$s;$c\",'Machine')}"
方法 2:インストーラーによるインストール
- Python公式サイト(https://www.python.org/downloads/)にアクセスし、「Download Python 3.x.x」ボタンからWindows用インストーラーをダウンロードする。
- ダウンロードしたインストーラーを実行する。
- 初期画面の下部に表示される「Add python.exe to PATH」にチェックを入れてから「Customize installation」を選択する。このチェックを入れ忘れると、コマンドプロンプトから
pythonコマンドを実行できない。 - 「Install Python 3.xx for all users」にチェックを入れ、「Install」をクリックする。
インストールの確認
コマンドプロンプトで以下を実行する。
python --version
バージョン番号(例:Python 3.12.x)が表示されればインストール成功である。「'python' は、内部コマンドまたは外部コマンドとして認識されていません。」と表示される場合は、インストールが正常に完了していない。
必要なライブラリのインストール [クリックして展開]
管理者権限でコマンドプロンプトを起動する
(手順:Windowsキーまたはスタートメニュー → cmd と入力 → 右クリック → 「管理者として実行」)。
続いて以下を実行する。--no-user はユーザーディレクトリへのインストールを抑止し,システム全体(全ユーザー向け)にインストールするためのオプションである。
pip install -U --no-user flask pandas
6. Employees Sample データベース(SQLite版)について
このデータベースは,MySQL Employees Sample Database を SQLite 形式に変換したものであり,GitHub 上の bytebase/employee-sample-database リポジトリで公開されている。出典と著作権表示は以下のとおりである。
データの出典: MySQL Employees Sample Database(原著者: Fusheng Wang, Carlo Zaniolo。リレーショナルスキーマ: Giuseppe Maxia。データ変換: Patrick Crews)
This work is licensed under the Creative Commons Attribution-Share Alike 3.0 Unported License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/ or send a letter to Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA.
SQLite adaptation: bytebase/employee-sample-database (MIT License)
7. 演習1.Employees Sample データベースのダウンロード
手順
① 次のコードを実行(メモ帳を用いる場合は a.py のようなファイル名で保存して実行)する。データベースファイル employee.db がカレントディレクトリにダウンロードされる。以降の演習も,このカレントディレクトリで実行する。
import urllib.request
import os
urllib.request.urlretrieve(
'https://raw.githubusercontent.com/bytebase/employee-sample-database/main/sqlite/dataset_small/employee.db',
'employee.db')
print('exists:', os.path.exists('employee.db'))
print('size:', os.path.getsize('employee.db'))
ヒント
urllib.request.urlretrieve(URL, ファイル名)は,第1引数の URL からファイルを取得し,第2引数のファイル名で保存する。os.path.existsはファイルの有無を,os.path.getsizeはファイルサイズ(バイト単位)を返す。
考察ポイント
- 表示された
existsがTrue,sizeが正の値であることを確認する。
8. 演習2.単一URLに対する応答
手順
① 次のコードを実行(メモ帳を用いる場合は a.py のようなファイル名で保存して実行)する。
from flask import Flask
app = Flask(__name__)
@app.route('/db')
def tables():
return 'welcome'
app.run(host='localhost', port=8080, debug=True)
② Webブラウザで http://localhost:8080/db にアクセスし,「welcome」と表示されることを確認する。
ヒント
- Webサーバを停止するには,コマンドプロンプトで Ctrl+C を押す。
- Windows でうまく動作しない場合,ファイアウォールがポート番号 8080 の通信を遮断している可能性がある。その場合はファイアウォールの設定でポート番号 8080 を許可する。
考察ポイント
@app.route('/db')で指定した URL(/db)と,関数tablesの戻り値('welcome')が,ブラウザの表示にどう対応しているかを確認する。http://localhost:8080/やhttp://localhost:8080/otherなど,登録していない URL にアクセスした場合の表示を確認する。
9. 演習3.戻り値の変更
手順
① 次のコードを実行(メモ帳を用いる場合は a.py のようなファイル名で保存して実行)する。演習2 との違いは,関数 tables の戻り値を 'welcome' から 'hoge' に変えた点だけである。
from flask import Flask
app = Flask(__name__)
@app.route('/db')
def tables():
return 'hoge'
app.run(host='localhost', port=8080, debug=True)
② Webブラウザで http://localhost:8080/db にアクセスし,「hoge」と表示されることを確認する。
ヒント
debug=Trueで起動した Flask は,ファイル保存時に自動で再読み込みされる。再読み込みされない場合は,コマンドプロンプトで Ctrl+C を押して停止し,再度実行する。
考察ポイント
- 関数の戻り値の変更が,ブラウザの表示にどう反映されるかを確認する。
10. 演習4.データベースのテーブル一覧の表示
手順
① 次のコードを実行(メモ帳を用いる場合は a.py のようなファイル名で保存して実行)する。employee.db と同じカレントディレクトリで実行すること。
from flask import Flask
import sqlite3
import pandas
app = Flask(__name__)
DB = 'employee.db'
def query(sql):
c = sqlite3.connect(DB)
df = pandas.read_sql(sql, c)
c.close()
return df
@app.route('/db')
def tables():
df = query("SELECT * FROM sqlite_master WHERE type='table';")
return '<pre>%s</pre>' % df.to_string()
app.run(host='localhost', port=8080, debug=True)
② Webブラウザで http://localhost:8080/db にアクセスし,テーブル一覧が表示されることを確認する。
ヒント
query関数は,SQL 文を受け取り,結果をデータフレームとして返す(同じ処理を複数の URL で使うため関数化している)。<pre>...</pre>は HTML の整形済みテキストタグであり,テーブルの整形をブラウザ上で保つために使用する。employee.dbは,このコードと同じカレントディレクトリに配置されている必要がある。
考察ポイント
- 表示されたテーブル一覧(
employee,department,dept_emp,dept_manager,title,salaryなど)を確認する。 sqlite_masterの各列(type,name,tbl_name,sqlなど)に格納されている情報を確認する。
11. 演習5.URLによる処理の振り分け
手順
① 次のコードを実行(メモ帳を用いる場合は a.py のようなファイル名で保存して実行)する。employee.db と同じカレントディレクトリで実行すること。
from flask import Flask
import sqlite3
import pandas
app = Flask(__name__)
DB = 'employee.db'
def query(sql):
c = sqlite3.connect(DB)
df = pandas.read_sql(sql, c)
c.close()
return df
@app.route('/db')
def tables():
df = query("SELECT * FROM sqlite_master WHERE type='table';")
return '<pre>%s</pre>' % df.to_string()
@app.route('/db/departments')
def departments():
df = query("SELECT * FROM department;")
return '<pre>%s</pre>' % df.to_string()
app.run(host='localhost', port=8080, debug=True)
② Webブラウザで http://localhost:8080/db にアクセスし,テーブル一覧が表示されることを確認する。
③ Webブラウザで http://localhost:8080/db/departments にアクセスし,department テーブルのデータが表示されることを確認する。
ヒント
- URL のパス部分は
/db/departments(複数形)であるが,SQL 文で参照するテーブル名はdepartment(単数形)である。URL の名称とテーブル名は独立に決められる。 @app.routeを複数記述することで,URL ごとに異なる関数を割り当てられる。
考察ポイント
- 同一の Webサーバが,URL の違いに応じて異なる処理(テーブル一覧の表示と
departmentテーブルの内容表示)を行うことを確認する。 - 演習4 の
tables関数と本演習のdepartments関数を見比べ,URL 追加に必要な記述(@app.routeと関数定義の追加)を確認する。 - 他のテーブル(
employee,salaryなど)についても同様にルートを追加し,表示を確認する。