目次
前提条件
┣ app.py
︙
┗ templates/
┗ index.html
ターミナル(コマンドプロンプト)のカレントディレクトリは、 flaskフォルダにあるものとします。
app.py
# -*- coding: utf-8 -*-
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def index():
return render_template('index.html')
if __name__ == '__main__':
app.run()
index.html
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Hello Jinja2</title>
</head>
<body>
<h1>Hello Jinja2</h1>
<p>Jinja2でHTMLファイルを読み込みことに成功しました。</p>
</body>
</html>
pandas.Seriesを渡す
結論から言うと、Jinja2テンプレートエンジンでpandas.Series
を直接送ることはできません!
では、どうするか
pandas.Series
をPythonのリストに変換させる必要があります。
import pandas as pd # => pip install pandas
index = ['2019-12-29', '2019-12-30', '2019-12-31', '2020-01-01']
data = [12.4, 15.2, 7.9, 9.8]
s = pd.Series(data=data, index=index)
pandas.Series
の値が変数s
に格納されているとすると、以下のテーブルの書式に従い、シリーズのコンテンツやインデックスをPythonのリストとして取得することができます。
書式 | 戻り値の型 | 説明 |
---|---|---|
s.values.tolist() |
1次元配列 | シリーズのコンテンツ |
s.index.tolist() |
1次元配列 | シリーズのインデックス |
サンプルプログラム
# 中略
@app.route('/')
def index():
s_values = s.values.tolist() # 1次元配列(中身)
s_index = s.index.tolist() # 1次元配列(インデックス)
return render_template('index.html', \
s_values = s_values, \
s_index = s_index)
<!-- 中略 -->
<body>
<h1>{{ title }}</h1>
<ul>
{%- for i in s_index %}
<li>{{ i|e }}, {{ s_values[loop.index0]|e }}</li>
{%- endfor %}
</ul>
</body>
Jinja2テンプレートエンジンのforループでloop.index0
を使って、サーバーサイドから受け取った配列s_values
の番号を指定しているところがポイントです。
forループの中で使えるloop
変数についてもっと詳しく知りたい人はこの記事からどうぞ
pandas.DataFrameを渡す
結論から言うと、Jinja2テンプレートエンジンでpandas.DataFrame
を直接送ることはできません!
pandas.Series
のときと同様に、pandas.DataFrame
をPythonのリストに変換させる必要があります。
import pandas as pd # => pip install pandas
index = ['2019-12-29', '2019-12-30', '2019-12-31', '2020-01-01']
columns = ['最高気温', '最低気温', '天候']
data = [[12.4, 5.1, '曇り'], [15.2, 12.0, '曇り'], [7.9, 7.2, '晴れ'], [9.8, 1.6, '晴れ']]
df = pd.DataFrame(data=data, columns=columns, index=index)
pandas.DataFrame
の値が変数df
に格納されているとすると、以下のテーブルの書式に従い、データフレームのコンテンツやヘッダー、インデックスをPythonのリストとして取得することができます。
書式 | 戻り値の型 | 説明 |
---|---|---|
df.values.tolist() |
2次元配列 | データフレームのコンテンツ |
df.columns.tolist() |
1次元配列 | データフレームのヘッダー |
df.index.tolist() |
1次元配列 | データフレームのインデックス |
テーブルのCSSは見やすさを考慮して、Jupyter Notebookと同じデザインを起用しています。
table {
margin-left: 2em;
border: none;
border-collapse: collapse;
border-spacing: 0;
color: black;
font-size: 12px;
table-layout: fixed;
text-align: right;
padding: 0.4em;
}
thead {
border-bottom: 1px solid black;
vertical-align: bottom;
}
tbody tr:nth-child(odd) {
background: #f5f5f5;
}
tr, th, td {
text-align: right;
vertical-align: middle;
padding: 0.5em 0.5em;
line-height: normal;
white-space: normal;
max-width: none;
border: none;
}
th {
font-weight: bold;
}
中身(コンテンツ)のみ渡す
サンプルプログラム
# 中略
@app.route('/')
def index():
df_values = df.values.tolist() # 2次元配列(中身)
return render_template('index.html', \
df_values = df_values)
<!-- 中略 -->
<body>
<h1>中身のみ渡す</h1>
<table>
<tbody>
{%- for i in df_values %}
<tr>{% for j in i %}<td>{{ j|e }}</td>{% endfor %}</tr>
{%- endfor %}
</tbody>
</table>
</body>
中身とヘッダー(columns)を渡す
サンプルプログラム
# 中略
@app.route('/')
def index():
df_values = df.values.tolist() # 2次元配列(中身)
df_columns = df.columns.tolist() # 1次元配列(ヘッダー)
return render_template('index.html', \
df_values = df_values, \
df_columns = df_columns)
<!-- 中略 -->
<body>
<h1>ヘッダー(columns)も渡す</h1>
<table>
<thead>
<tr>{%- for i in df_columns %}<th>{{ i|e }}</th>{%- endfor %}</tr>
</thead>
<tbody>
{%- for i in df_values %}
<tr>{% for j in i %}<td>{{ j|e }}</td>{% endfor %}</tr>
{%- endfor %}
</tbody>
</table>
</body>
中身とインデックス(index)を渡す
サンプルプログラム
# 中略
@app.route('/')
def index():
df_values = df.values.tolist() # 2次元配列(中身)
df_index = df.index.tolist() # 1次元配列(インデックス)
return render_template('index.html', \
df_values = df_values, \
df_index = df_index)
<!-- 中略 -->
<body>
<h1>インデックス(index)も渡す</h1>
<table>
<tbody>
{%- for i in df_values %}
<tr><th>{{ df_index[loop.index0]|e }}</th>{% for j in i %}<td>{{ j|e }}</td>{% endfor %}</tr>
{%- endfor %}
</tbody>
</table>
</body>
中身とヘッダーとインデックスを渡す
サンプルプログラム
# 中略
@app.route('/')
def index():
df_values = df.values.tolist() # 2次元配列(中身)
df_columns = df.columns.tolist() # 1次元配列(ヘッダー)
df_index = df.index.tolist() # 1次元配列(インデックス)
return render_template('index.html', \
df_values = df_values, \
df_columns = df_columns, \
df_index = df_index)
<!-- 中略 -->
<body>
<h1>ヘッダーとインデックスも渡す</h1>
<table>
<thead>
<tr>{%- for i in df_columns %}<th>{{ i|e }}</th>{%- endfor %}</tr>
</thead>
<tbody>
{%- for i in df_values %}
<tr><th>{{ df_index[loop.index0]|e }}</th>{% for j in i %}<td>{{ j|e }}</td>{% endfor %}</tr>
{%- endfor %}
</tbody>
</table>
</body>
連載目次:FlaskでWebアプリケーションを開発するためのロードマップ
入門編:10記事
入門編の10記事を順に読んでいけば、FlaskでWebアプリケーションを開発する必要最小限のことが学べます。
簡単なアプリケーションであれば、セキュリティ上の観点を考慮しなかった場合公開できるでしょう。
- Flaskを『ローカルで開発する環境構築』から『プログラムの実行まで』を一通り
FlaskでWebアプリケーションを作る『全体の流れ』を大まかに理解する- Flaskのrender_templateでHTML・CSS・JavaScriptファイルを読み込む
- サーバーサイドからクライアントサイドに変数(値・リスト・辞書型配列)を渡す
- クライアントサイドで変数を処理(アサイン、フィルター、エスケープ)する
- クライアントサイドで条件分岐(if)とループ(for in)を使って、コードを簡素化する
- クライアントサイド(form)からサーバーサイドにテキストや各種コントロール、ファイルを渡す
- テンプレート継承でHTMLファイルを役割ごとに分割する
データベースに接続するデプロイする
実践編
実践編の記事では、FlaskでWebアプリケーションを公開するために欠かせないセキュリティのことや実践的なテクニックを紹介しています。
ここまで読み込めば、あとはアイディア次第でいろんなWebアプリケーションを公開できるでしょう!
セッションCookieメソッドベース・ディスパッチベーシック認証・Digest認証ログイン機能- サーバーサイドからクライアントサイドにpandas.Series、pandas.DataFrameを渡す
- クライアントサイド(form)からPOSTされた1、2次元配列を受け取る
matplotlibを使うBootstrap4を使うフォームの非同期通信(Ajax, jQuery)