続・玩式草子 ―戯れせんとや生まれけん―

第8回 ウィスキー・ボトル・ブルース(2番)

この記事を読むのに必要な時間:およそ 4 分

requestオブジェクト

前節のスクリプトの17,18行目のように,クライアントから<form>タグやURIの引数として送られてくるデータ(リクエスト・パラメータ)は,Bottleではrequestオブジェクトを経由して受け取ります。

requestオブジェクトを利用するには,先のスクリプトの3行目のように,"from bottle import ..."の行でrequestモジュールをimportしておきます。

このモジュールをimportすれば,前節のスクリプトのように<form>タグ経由でPOSTメソッドを使って送られてくるパラメータを,<input>タグなどのname属性をキーワードに,request.forms.get(name)として取り出すことができます。

一方,GETメソッドでURLパラメータとして送られてくる値を取り出すには,同じrequestオブジェクトのrequest.query.get(name)を使います。

Bottleでは,これらリクエスト時に送られてくるパラメータは,Pythonの辞書型を拡張したFormsDictと呼ばれるクラスに収められ,辞書型のように扱うことも,メソッドを使って"request.forms.get(name)"のように取り出すことも可能です。

Bottleがどのようにリクエスト・パラメータを扱うか確認するために,こんなスクリプトを書いてみました。

 1  #!/usr/bin/python
 2  
 3  from bottle import route,run,request, template
 4  
 5  @route('/check')
 6  @route('/check', method='POST')
 7  def key_check():
 8      print("request.query:",end="")
 9      print(vars(request.query))
10  
11      print("request.forms:",end="")
12      print(vars(request.forms))
13  
14      print("request.params:",end="")
15      print(vars(request.params))
16  
17      try:
18          len(request.forms.get('r_name'))
19          r_name = request.forms.get('r_name')
20          h_name = request.forms.get('h_name')
21          return template('Hello {{name}} a.k.a. {{nick}}', name=r_name, nick=h_name)
22      except:
23          return '''
24      <form action="/check" method="post">
25          real name:   <input name="r_name" type="text" /> <br>
26          handle name: <input name="h_name" type="text" />
27          <input value="send" type="submit" />
28      </form>
29      '''
30  
31  run(host='localhost', port=8080, reloader=True, debug=True)

このスクリプトでは"http://localhost:8080/check"というURIを,5行目でGETメソッド,6行目でPOSTメソッドを指定して,両メソッドとも7行目のkey_check()という関数に結びつけています。

8行目から15行目は,requestオブジェクトにどういうデータが収められているかを観察するためのprint文で,これらprint文の出力は,ブラウザではなくスクリプトを起動したコンソールに出力されます。

Bottleでは,return文で返したデータしかクライアントには送られません。

17行目から29行目は,POSTメソッドでデータが送られてきた場合はその内容を表示し(18~21行目)⁠GETメソッドでリクエストされた場合はPOSTメソッド用の<form>タグを返す(23~28行目)⁠という処理です。

このスクリプトを起動して,ブラウザから"http://localhost:8080/check"にアクセスすると,ブラウザ側には入力を促す<form>タグの画面が,スクリプトを起動したコンソールには空っぽのrequestオブジェクトの中身が,それぞれ表示されます。

$ python sample_02.py
Bottle v0.13-dev server starting up (using WSGIRefServer())...
Listening on http://localhost:8080/
Hit Ctrl-C to quit.

request.query:{'dict': {}}
request.forms:{'dict': {}, 'recode_unicode': True}
request.params:{'dict': {}}
127.0.0.1 - - [21/Apr/2019 12:30:36] "GET /check HTTP/1.1" 200 222

図4 GETメソッドでアクセス

図4 GETメソッドでアクセス

<form>タグに何かテキストを入力して送信すると,request.formsとrequest.paramsに辞書型のデータが収められ,ブラウザには21行目の"Hello"メッセージが表示されます。

request.query:{'dict': {}}
request.forms:{'dict': {'r_name': ['kojima'], 'h_name': ['isle']}, 'recode_unicode': True}
request.params:{'dict': {'r_name': ['kojima'], 'h_name': ['isle']}}
127.0.0.1 - - [21/Apr/2019 12:33:49] "POST /check HTTP/1.1" 200 24

図5 POSTメソッドでデータを送信

図5 POSTメソッドでデータを送信

一方,URLパラメータを追加して,"http://localhost:8080/check?r_name=kojima&h_name=isle" のようにアクセスしてみると,request.queryとrequest.paramsに辞書型のデータが収まります。

request.query:{'dict': {'r_name': ['kojima'], 'h_name': ['isle']}}
request.forms:{'dict': {}, 'recode_unicode': True}
request.params:{'dict': {'r_name': ['kojima'], 'h_name': ['isle']}}
127.0.0.1 - - [21/Apr/2019 12:37:25] "GET /check?r_name=kojima&h_name=isle HTTP/1.1" 200 222

図6 GETメソッドでURLパラメータを送信

図6 GETメソッドでURLパラメータを送信

このように,BottleではURLパラメータやPOSTメソッドで送られたパラメータは,request.paramsオブジェクトに収められると共に,メソッドに応じてrequest.queryオブジェクトかrequest.formsオブジェクトに収められ,スクリプト内では"request.query.get(name)"といったメソッドやPythonの辞書型のデータとしてname属性をキーに"request.query['name']" といった形で利用できます。

なお,上記スクリプトでは <form>タグに日本語を入れると文字化けしてしまいます。これは,HTTPの仕様上,UTF-8な文字列も単なるバイト列と見做して,Latin-1な文字コードで表示してしまうためで,日本語のようなマルチバイト文字を扱う場合は,"request.query.getunicode(r_name)"や"request.forms.getunicode(h_name)"のように,getメソッドの代わりにgetunicodeメソッドを使う必要があります。


Bottleの作者,Marcel Hellkampさんが,なぜこのコードを"Bottle"と名付けたかは,ドキュメント類をあれこれ調べたものの,よくわかりませんでした。

しかしながら,Bottleのホームページのロゴなどを見ると,化学実験のような丸底フラスコが印象的で,みんながあれこれコードを書くための器,くらいのつもりで"Bottle"と名付けたような気がします。

一方,Bottle同様,Python上で開発された"Flask"というmicro Webフレームワークも存在し,こちらは"Bottle(瓶)"に対する"Flask(フラスコ)"という言葉遊びで命名されたそうです。

呑兵衛の筆者には,"ボトル"とか"フラスコ"と言われると,⁠スキットル」と呼ばれる,ズボンの尻ポケットに突っ込んでおくような,携帯タイプのウィスキー瓶を連想してしまいます(苦笑)⁠

更なる連想で,今回のタイトルに借用した「ウィスキー・ボトル・ブルース」は,シンガー・ソングライターのイルカさんの2枚目のアルバム「小さな空」に入っている楽曲で,場末の飲み屋の裏口に廃棄されたウィスキー瓶たちが,ワイワイガヤガヤと自分たちの境遇を語る楽しい歌です。興味を持たれた方はぜひ聞いてみてください。

著者プロフィール

こじまみつひろ

Plamo Linuxとりまとめ役。もともとは人類学的にハッカー文化を研究しようとしていたものの,いつの間にかミイラ取りがミイラになってOSSの世界にどっぷりと漬かってしまいました。最近は田舎に隠棲して半農半自営な生活をしながらソフトウェアと戯れています。

URLhttp://www.linet.gr.jp/~kojima/Plamo/index.html