【Flask】クライアントサイド(form)からPOSTされた1、2次元配列を受け取る

前提条件

CHECK.1
ディレクトリ
ディレクトリ
flask/
app.py

┗ templates/
index.html

ターミナル(コマンドプロンプト)のカレントディレクトリは、 flaskフォルダにあるものとします。

CHECK.2
app.py
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()
CHECK.3
index.html
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>
CHECK.4
動作確認
ターミナル
$ python app.py

http://127.0.0.1:5000/

END

1次元配列を受け取る

HTML
<form action="/" method="POST" enctype="multipart/form-data">
	<input type="hidden" name="arr" value="[1,2,3,4,5]"> <!-- 文字列として送信される -->	
	<input type="submit" value="送信">
</form>

HTMLのform要素で配列を直接送ることはできません。

では、どうするか

サーバーサイドで1次元配列風の文字列を受け取って、それをPythonの1次元配列に無理やり変換させます。

具体的には、文字列として受け取った1次元配列を正規表現(reモジュールのsubメソッド)でカッコや空白文字を取り除いて、標準の組み込み関数のsplitメソッドで文字列を配列に変換します。

Python
from flask import Flask, render_template, request
import re

# 1次元配列風の文字列をフォームから受け取る
str1 = request.form.get('arr')

# 文字列→1次元配列
arr1 = re.sub('(\[|\'|\]|\s)', '', str1).split(',')

サンプルプログラム

index.html
<!-- 中略 -->
<body>
	{%- set arr = [1,2,3,4,5] %}
	<form action="/" method="POST" enctype="multipart/form-data">
		<input type="hidden" id="arr" name="arr" value="{{ arr }}">	
		<input type="submit" value="送信">
	</form>
</body>
app.py
# 中略
@app.route('/', methods=['POST'])
def post():
	
	# 1次元配列風の文字列をフォームから受け取る
	str1 = request.form.get('arr')
	
	# 文字列→1次元配列
	arr1 = re.sub('(\[|\'|\]|\s)', '', str1).split(',')
	print("arr1", arr1, type(arr1)) # ここでチェック
	# => arr1 ['1', '2', '3', '4', '5'] 

2次元配列を受け取る

HTML
<form action="/" method="POST" enctype="multipart/form-data">
	<input type="hidden" name="arr" value="[[1,2,3],['a','b','c'],['あ','い','う']]">
	<input type="submit" value="送信">
</form>

1次元配列のときと同様に、HTMLのform要素で配列を直接送ることはできません。

考え方も同じで、サーバーサイドで2次元配列風の文字列を受け取って、それをPythonの2次元配列に無理やり変換させます。

Python
from flask import Flask, render_template, request
import re

# 2次元配列風の文字列をフォームから受け取る
str2 = request.form.get('arr')

# 文字列→2次元配列?
arr2 = re.sub('(\[|\'|\]|\s)', '', str2).split(',')

しかし、残念ながら、この方法だと1次元配列が生成されてしまいます。

Python
print(arr2)
# => ['1', '2', '3', 'a', 'b', 'c', 'あ', 'い', 'う']

この配列でいうと3つの要素ごとに句切れば、欲しい2次元配列が取得することができますね。

Python
from flask import Flask, render_template, request
import re

# 2次元配列風の文字列をフォームから受け取る
str2 = request.form.get('arr')

# 文字列→1次元配列
arr1 = re.sub('(\[|\'|\]|\s)', '', str2).split(',')

# 区切り文字数
n = 3

# 1次元配列→2次元配列
arr2 = [arr1 [i:i + n] for i in range(0, len(arr1), n)]
Python
print(arr2)
# => [['1', '2', '3'], ['a', 'b', 'c'], ['あ', 'い', 'う']]

この方法で、2次元配列風の文字列をフォームから受け取って、2次元配列に変換することに成功しましたが、区切り文字数をn = 3と手動で設定しているところが汎用性が低いので、ここも計算させましょう。

この値はクライアントサイド側(Jinja2)のlengthフィルターで求めると簡単です。

サンプルプログラム

index.html
<!-- 中略 -->
<body>
	{%- set arr = [[1,2,3],['a','b','c'],['あ','い','う']] %}
	<form action="/" method="POST" enctype="multipart/form-data">
		<input type="hidden" name="arr" value="{{ arr }}">
		<input type="hidden" name="num" value="{{ arr[0]|length }}">
		<input type="submit" value="送信">
	</form>
</body>
app.py
# 中略
@app.route('/', methods=['POST'])
def post():
	
	# 2次元配列風の文字列をフォームから受け取る
	str2 = request.form.get('arr')

	# 文字列→1次元配列
	arr1 = re.sub('(\[|\'|\]|\s)', '', str2).split(',')

	# 区切り文字数をフォームから受け取る
	n = int(request.form.get('num'))

	# 1次元配列→2次元配列
	arr2 = [arr1 [i:i + n] for i in range(0, len(arr1), n)]
	print("arr2", arr2, type(arr2))
	# => arr2 [['1', '2', '3'], ['a', 'b', 'c'], ['あ', 'い', 'う']] 

連載目次:FlaskでWebアプリケーションを開発するためのロードマップ

入門編:10記事

入門編の10記事を順に読んでいけば、FlaskでWebアプリケーションを開発する必要最小限のことが学べます。

簡単なアプリケーションであれば、セキュリティ上の観点を考慮しなかった場合公開できるでしょう。

実践編

実践編の記事では、FlaskでWebアプリケーションを公開するために欠かせないセキュリティのことや実践的なテクニックを紹介しています。

ここまで読み込めば、あとはアイディア次第でいろんなWebアプリケーションを公開できるでしょう!

  1. セッション
  2. Cookie
  3. メソッドベース・ディスパッチ
  4. ベーシック認証・Digest認証
  5. ログイン機能
  6. サーバーサイドからクライアントサイドにpandas.Series、pandas.DataFrameを渡す
  7. クライアントサイド(form)からPOSTされた1、2次元配列を受け取る
  8. matplotlibを使う
  9. Bootstrap4を使う
  10. フォームの非同期通信(Ajax, jQuery)