フォームによるクライアント・サーバ間データ通信
ここでは、クライアント(Webページを見ているユーザ)から与えられた入力を、pythonの変数として獲得し、出力に反映させる方法について述べます。
まず、以下のコードを見てください。
from bottle import route, run, get, post, request # クライアントからサーバへデータを与えるためのページ @route('/') def befor_func(): t = '<!DOCTYPE html><html>' t = t + '<head>' t = t + '<title> PythonHTML </title>' t = t + '<meta http-equiv="content-type" charset="utf-8">' t = t + '</head>' t = t + '<body>' ############# フォーム開始 ############# t = t + '<form action="/output" method="post">' # テキスト入力 t = t + '<p>' t = t + '<h3>テキスト入力:</h3>' t = t + '<input type="text" name="input_text">' t = t + '</p>' # チェックボタン t = t + '<p>' t = t + '<h3>チェックボタン:</h3>' t = t + '<input type="checkbox" name="input_check" value="1"> りんご' t = t + '<input type="checkbox" name="input_check" value="2" checked> みかん' t = t + '</p>' # ラジオボタン t = t + '<p>' t = t + '<h3>ラジオボタン:</h3>' t = t + '<input type="radio" name="input_radio" value="1"> 美味しい' t = t + '<input type="radio" name="input_radio" value="2" checked> まずい' t = t + '</p>' # スライダー t = t + '<p>' t = t + '<h3>スライダー:</h3>' t = t + '<input type="range" name ="input_range" value="1" min="1" max="10" step="0.1">' t = t + '</p>' # 数字 t = t + '<p>' t = t + '<h3>数字:</h3>' t = t + '<input type="number" name ="input_num" value="1" min="1" max="10" step="0.1">' t = t + '</p>' # カラー t = t + '<p>' t = t + '<h3>カラー:</h3>' t = t + '<input type="color" name ="input_col">' t = t + '</p>' # 送信ボタン t = t + '<input value="push" type="submit" />' t = t + '</form>' ############# フォーム終了 ############# t = t + '</body>' t = t + '</html>' return t # クライアントから受け取ったデータを受け取るページ @post('/output') def aft_func(): # フォームの入力を取得 output_text = request.forms.input_text output_check = request.forms.getlist("input_check") # 複数選択の場合があるため output_radio = request.forms.input_radio output_range = request.forms.input_range output_num = request.forms.input_num output_col = request.forms.input_col t = '<!DOCTYPE html><html>' t = t + '<head>' t = t + '<title> PythonHTML </title>' t = t + '<meta http-equiv="content-type" charset="utf-8">' t = t + '</head>' t = t + '<body>' t = t + "<p>あなたの回答:</p>" t = t + "テキスト: " + output_text + "<br>" t = t + "チェックボックス: " + str(output_check) + "<br>" t = t + "ラジオボタン: " + output_radio + "<br>" t = t + "スライダー: " + output_range + "<br>" t = t + "数字: " + output_num + "<br>" t = t + "カラー: " + output_col + "<br>" t = t + '</body>' t = t + '</html>' return t # サーバの起動(一番下に書くこと) run(reloader=True, port=9999, debug=True)
フォームの定義(14行目〜58行目):
フォームと呼ばれる、ユーザの入力を行う領域を定義しています。ボタンを押すと15行目で定義されているように、「/output」へと飛ぶようになっています。「/output」に相当するページは、67行目以降に定義されています。飛ぶ前のurlは「http://xxx.xxx.xxx.xxx:9999/」であり、飛んだあとのurlは「http://xxx.xxx.xxx.xxx:9999/output」となります。xxx.xxx.xxx.xxxはサーバを起動した時のターミナルに出力される数字列となります。9999はポート番号であり、97行目で定義されています。ポート番号の後ろの「/」「/output」という部分は、5行目、67行目にて定義しています。
テキスト入力欄の作成(17行目〜21行目):
inputタグのtypeにtextと入れると、テキスト入力欄が作成できます。nameで指定した文字列(input_text)に対し、入力された文字列が貯蔵されます。
チェックボックスの作成(23行目〜28行目):
inputタグのtypeにcheckboxと入れると、チェックボックスが作成できます。チェックボックスは複数選択でるユーザインタフェースとなります。nameで指定した文字列(input_check)に対し、入力された文字列が貯蔵されます。27行目に、checkedという文字が見えます。これは初期からチェックしておくという意味があります。りんごにチェックが入れば、valueにあるように、input_checkが1を保持し、みかんにチェックが入ればinput_checkが2を保持します。りんごとみかんにチェックが入っているときは、input_checkが配列となり[1,2]を保持するようになります。
ラジオボタンの作成(30行目〜35行目):
チェックボックスとほぼ同じです。ただチェックボックスとは異なり、複数選択ができません。したがって、input_radioは配列とはなりません。
スライダーの作成(37行目〜41行目):
inputタグのtypeにrangeを指定すると、スライダーを用意できます。minとmaxはスライダーの最小と最大です。stepは分割幅を表します。valueは初期値です。
数字の作成(43行目〜47行目):
inputタグのtypeにnumberを指定すると、数字の選択欄が出ます。min, max, stepで最小、最大、分割幅を指定することができます。valueは初期値です。
カラーの作成(49行目〜53行目):
inputタグのtypeにcolorを指定すると、色を選択できるようになります。デザイン系の研究や感性評価などで使いそうですね。
入力データの取得(70行目〜76行目):
name領域に指定された変数(input_colorなど)に対し、request.forms.を付与すると、htmlのデータがpythonの変数として取得できます。チェックボックスのみ複数選択可能ですから、配列として取得する必要性があるので、少し異なる書き方をしています。
htmlの作成(78行目〜92行目):
最後に、pythonの文字列でhtmlを生成します。returnにてこの文字列を返すと、ページが表示されます。
理解できたら、ターミナルで「python3 sample.py」とうち、実行結果を確認してみてください。ターミナルに出るxxx.xxx.xxx.xxxx:9999をブラウザに打ち込めばokです。
for文などで、html側の変数をpythonに連続的に渡したい場合は、以下のようにします。
a = [] for i in range(0, 10): a.append(request.forms.get("input_text"+str(i))
GetとPostについて
GetとPostは、HTMLでのデータの受け渡しを意味します。これには以下の違いがあります。
- Get: URLに対して送信するデータをそのまま記載する送受信方法
- Post: URLに送信するデータを記載しない送受信方法
これをみてわかるように、基本的にはPostにより送信した方が安全です。上のプログラムでは、postメソッドによりデータの受け渡しをしています。これを確認するため、以下の行を確認してみてください。
postメソッドによるデータの受け渡し:
- 15行目: データ送信側で、formのmethodがpostとなっている。
- 67行目: データ受信側のページが、post指定されている。
- 71〜76行目: formsで、データを受け取っている。
15行目より、送信側のformによりpost指定されており、67行目における受け取り側のページでもpost指定されていますね。post指定されているデータの送信は、formsを用いて受け取りを行います。
Getメソッドを使う場合
以下は、getメソッドによるデータの送受信です。上のコードに対して、以下の変更点があるのみです。
getメソッドによるデータの受け渡し:
- 15行目: データ送信側で、formのmethodがgetとなっている。
- 67行目: データ受信側のページが、get指定されている。
- 71〜76行目: queryで、データを受け取っている。
送信側と受信側がどちらもgetになっています。要するに、メソッドをきちんと合わせればokです。なお、getメソッドによるデータをpythonで受け取るには、queryを使用します。これを実行し、URLにユーザの選択肢が表示されていることを確認してみてください。
from bottle import route, run, get, post, request # クライアントからサーバへデータを与えるためのページ @route('/') def befor_func(): t = '<!DOCTYPE html><html>' t = t + '<head>' t = t + '<title> PythonHTML </title>' t = t + '<meta http-equiv="content-type" charset="utf-8">' t = t + '</head>' t = t + '<body>' ############# フォーム開始 ############# t = t + '<form action="/output" method="get">' # テキスト入力 t = t + '<p>' t = t + '<h3>テキスト入力:</h3>' t = t + '<input type="text" name="input_text">' t = t + '</p>' # チェックボタン t = t + '<p>' t = t + '<h3>チェックボタン:</h3>' t = t + '<input type="checkbox" name="input_check" value="1"> りんご' t = t + '<input type="checkbox" name="input_check" value="2" checked> みかん' t = t + '</p>' # ラジオボタン t = t + '<p>' t = t + '<h3>ラジオボタン:</h3>' t = t + '<input type="radio" name="input_radio" value="1"> 美味しい' t = t + '<input type="radio" name="input_radio" value="2" checked> まずい' t = t + '</p>' # スライダー t = t + '<p>' t = t + '<h3>スライダー:</h3>' t = t + '<input type="range" name ="input_range" value="1" min="1" max="10" step="0.1">' t = t + '</p>' # 数字 t = t + '<p>' t = t + '<h3>数字:</h3>' t = t + '<input type="number" name ="input_num" value="1" min="1" max="10" step="0.1">' t = t + '</p>' # カラー t = t + '<p>' t = t + '<h3>カラー:</h3>' t = t + '<input type="color" name ="input_col">' t = t + '</p>' # 送信ボタン t = t + '<input value="push" type="submit" />' t = t + '</form>' ############# フォーム終了 ############# t = t + '</body>' t = t + '</html>' return t # クライアントから受け取ったデータを受け取るページ @get('/output') def aft_func(): # フォームの入力を取得 output_text = request.query.input_text output_check = request.query.getlist("input_check") # 複数選択の場合があるため output_radio = request.query.input_radio output_range = request.query.input_range output_num = request.query.input_num output_col = request.query.input_col t = '<!DOCTYPE html><html>' t = t + '<head>' t = t + '<title> PythonHTML </title>' t = t + '<meta http-equiv="content-type" charset="utf-8">' t = t + '</head>' t = t + '<body>' t = t + "<p>あなたの回答:</p>" t = t + "テキスト: " + output_text + "<br>" t = t + "チェックボックス: " + str(output_check) + "<br>" t = t + "ラジオボタン: " + output_radio + "<br>" t = t + "スライダー: " + output_range + "<br>" t = t + "数字: " + output_num + "<br>" t = t + "カラー: " + output_col + "<br>" t = t + '</body>' t = t + '</html>' return t # サーバの起動(一番下に書くこと) run(reloader=True, port=9999, debug=True)