【Flask Pandas】売上データからドロップダウンメニューで担当者を指定して抽出、ページに表示する
今回は、PandasのデータフレームをWebページに表示させます。
売上データから担当者を指定して表示させるアプリ。
実行環境
- Windows10
- Anaconda 4.11.0
- Python3.9.7
- VSCode 1.63.2
- 外部ライブラリ
- Flask 2.0.2
- colorama 0.4.4 (Windowsはたぶん手動でインストールが必要
- Pandas 1.3.5
アプリの仕様・操作手順など
df
No | 売上日 | 担当者 | 商品 | 単価 | 数量 | |
---|---|---|---|---|---|---|
0 | 1 | 2022-01-09 | 立花宗茂 | 牛乳 | 139 | 9 |
1 | 2 | 2022-01-08 | 島津義弘 | イチゴ | 416 | 6 |
2 | 3 | 2022-01-05 | 島津義弘 | 牛乳 | 281 | 3 |
3 | 4 | 2022-01-03 | 上杉謙信 | 牛乳 | 151 | 6 |
4 | 5 | 2022-01-06 | 豊臣秀吉 | 牛乳 | 474 | 1 |
... | ... | ... | ... | ... | ... | ... |
995 | 996 | 2022-01-01 | 上杉謙信 | バター | 150 | 10 |
996 | 997 | 2022-01-02 | 上杉謙信 | 卵 | 107 | 10 |
997 | 998 | 2022-01-10 | 織田信長 | 砂糖 | 462 | 8 |
998 | 999 | 2022-01-10 | 北条氏康 | 砂糖 | 416 | 10 |
999 | 1000 | 2022-01-05 | 毛利元就 | 卵 | 225 | 10 |
1000 rows × 6 columns
上のような売上データがあるとします。(顧客名を入れ忘れた
担当者を指定して、その担当者の売上テーブルを表示するアプリを作ります。
データフレームから条件抽出するにはdf.query()
かdf[df['カラム名']==値]
などを使えばできます。
- 織田信長氏の売り上げを抽出
df[df['担当者']=='織田信長']
No | 売上日 | 担当者 | 商品 | 単価 | 数量 | |
---|---|---|---|---|---|---|
12 | 13 | 2022-01-03 | 織田信長 | 卵 | 384 | 1 |
42 | 43 | 2022-01-09 | 織田信長 | イチゴ | 144 | 9 |
55 | 56 | 2022-01-10 | 織田信長 | 砂糖 | 455 | 3 |
72 | 73 | 2022-01-07 | 織田信長 | 小麦粉 | 138 | 4 |
73 | 74 | 2022-01-07 | 織田信長 | バター | 335 | 6 |
... | ... | ... | ... | ... | ... | ... |
970 | 971 | 2022-01-03 | 織田信長 | バター | 488 | 1 |
973 | 974 | 2022-01-10 | 織田信長 | バター | 437 | 2 |
981 | 982 | 2022-01-04 | 織田信長 | 卵 | 478 | 5 |
983 | 984 | 2022-01-01 | 織田信長 | チョコレート | 297 | 2 |
997 | 998 | 2022-01-10 | 織田信長 | 砂糖 | 462 | 8 |
108 rows × 6 columns
メニューから担当者を選択して、↑のような表をWebページに表示するのが今回の目標です。
データフレームに.to_html()
メソッドを付けると(df.to_html()
)、テーブルがhtmlコードに変換されます。そのオブジェクトをFlaskのテンプレートに渡せばテーブルを表示してくれるはずです。
- 担当者のユニークなリストを取得するには
df['担当者'].unique().tolist()
['立花宗茂', '島津義弘', '上杉謙信', '豊臣秀吉', '北条氏康', '毛利元就', '武田信玄', '織田信長', '徳川家康']
このリストをホームページに設置するドロップダウンメニューのselectタグ
に渡して、テンプレートエンジンの記法のfor文で回せばメニューが出来る。
アプリの操作手順
- ホームページに設置したドロップダウンメニューで担当者を選択し、送信する。
- 送信された担当者の売上データをデータフレームから抽出。
- テーブルで表示
ホームページ。ドロップダウンメニューで担当者を選択し、送信。
指定した担当者の売上データが表示される。
CSSでスタイル変更してみた。
ディレクトリ構成とファイルの中身
アプリはショボいんですが…
$ tree flask_sample flask_sample/ ├── app.py (Flaskを動かす) ├── static │ └── css │ └── style.css (表の装飾。試しに付けた) ├── templates │ ├── base.html (htmlページのメタ情報テンプレート) │ ├── index.html (ホームページ。入力欄とボタンを設置) │ └── result.html (表の出力ページ) └── uriage_data.py (データフレームの生成用) 3 directories, 6 files
app.py (Flaskを動かす用)
from flask import Flask, render_template, request from uriage_data import uriage app = Flask(__name__) # 売上データ df, tantou_list = uriage() # ホームページ @app.route('/') def index(): return render_template('index.html', tantou_list=tantou_list) # 入力値の表示ページ @app.route('/result', methods=['GET', 'POST']) def result(): # 担当者名を取得 tantou_name = request.form.get('tantousya') # データフレームから指定担当者の売上を抽出 df_tantou = df[df['担当者']==tantou_name] # 指定担当者のデータフレームをhtmlに変換 df_tantou = df_tantou.to_html() if request.method == 'POST': return render_template('result.html', tantou_name = tantou_name, dataframe = df_tantou) else: return render_template('index.html') if __name__=='__main__': app.run(debug=True)
uriage_data.py (データフレーム生成用)
app.pyの中に書いてもよかったのですが、読みにくいかなと思って分けました。
import pandas as pd import random random.seed(0) # 売上データを生成 def uriage(): df = pd.DataFrame({ 'No' : range(1, 1001), '売上日' : random.choices(pd.date_range(start='2022/1/1', freq='d', periods=10), k=1000), '担当者' : random.choices('織田信長 豊臣秀吉 徳川家康 毛利元就 北条氏康 武田信玄 上杉謙信 島津義弘 立花宗茂'.split(), k=1000), '商品' : random.choices('卵 牛乳 砂糖 小麦粉 バター チョコレート チーズ イチゴ'.split(), k=1000), '単価' : random.choices(range(100, 501), k=1000), '数量' : random.choices(range(1,11), k=1000) }) # 担当者をリストで取得 tantou_list = df['担当者'].unique().tolist() return df, tantou_list
base.html (htmlファイルのメタ情報)
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 rel="stylesheet" href="static/css/style.css"> <!-- タイトル --> <title>Flaskサンプル-{% block title %}{% endblock %}</title> </head> <!-- コンテンツ内容 --> <body> {% block content %} {% endblock %} </body> </html>
外部CSSファイルを用意したので、<link rel="stylesheet" href="static/css/style.css">
を付けました。「style.css」というファイルを「static/css/」に保存しているので。
これを書くだけで自動的にCSSファイルを読み込んでくれます。
index.html (ホームページ)
入力欄とボタンを設置
{% extends 'base.html' %} {% block title %}ホームページ{% endblock %} {% block content %} <form action="/result" method="POST"> <p>担当者: <select name="tantousya"> {% for i in tantou_list %} <option value="{{ i }}">{{ i }}</option> {% endfor %} </select> </p> <p><input type="submit" value="送信"></p> </form> {% endblock %}
selectタグ
のoptionタグ
でドロップダウンメニューを実装できます。
app.pyファイルから渡されたtantou_list
をfor文で回してメニューを作っています。
tantou_list
はuriage_data.py
で売上データフレームから取り出した担当者リスト。
送信ボタンを押すと、selectタグ
のname属性'tantousya'
はFlask側app.py
に送信されます。
result.html (指定担当者の表出力ページ)
{% extends 'base.html' %} <!-- タイトル表示 --> {% block title %}{{ tantou_name }}さんの売上データ{% endblock %} <!-- コンテンツ内容の表示 --> {% block content %} {{ dataframe | safe }} {% endblock %}
htmlテンプレートファイルにhtmlコードを渡すと、自動でエスケープされてページにコードが文字列で表示されてしまいます。
{{ dataframe | safe }}
と書いていますが、パイプ|
で繋いでsafe
とすることでエスケープが外れてhtmlコードが実行表示できるようになります。
style.css (指定担当者売上テーブルの装飾用)
html/css未学習のため、cssの書き方が分からず、適当にネットからコピペ・改造したものです。外部CSSの効かせ方を把握する目的。
.dataframe{ /*テーブルの縦幅が100px以上の場合スクロール*/ height: 100px; /*縦スクロール*/ overflow: scroll; } /* 一覧表の調整 */ td { border-bottom: 1px solid black; border-left: 1px solid black; border-right: 1px solid black; text-align: center; } th { background-color: #ddffeb; border-bottom: solid black; border-left: solid black; border-right: solid black; border-top: solid black; border-width: 2px; position: sticky; top: 0; text-align: center; } /* カラムの調整 */ .column { overflow: hidden;/*スクロール時にカラム名を固定*/ text-overflow: ellipsis; }
テーブルが縦長になったのでスクロールバーをつけようとしたが、よく分からない。とりあえずCSSは効いてるようだ。
実行
ターミナルでFlaskを実行し、サーバが起動したらブラウザでローカルホストの5000番にアクセス。
PS > python app.py
ブラウザで127.0.0.1:5000
かlocalhost:5000
にアクセス。
ホームページが表示される。あとは上の「アプリの操作手順」通り。
おわりに
通常、データはデータベースに登録し、表示する際にSQLなどで取り出すと思います。今回のようにデータフレームをテーブルにして表示することはしないとは思いますが、どうなるかの確認でした。
ショボいアプリなのにファイルが6個もある。変数値がファイルをまたいでアッチコッチに飛ぶので、設計書か何かで動作の全体像を把握しないと混乱する。Webやってる人スゲェ。
以上です。