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

第9回 ウィスキー・ボトル・ブルース(3番)

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

画像のアップロード

画像の表示ができるようになったので,次は画像ファイルをアップロードする機能を作ってみます。

ファイルのアップロードは,HTMLの<form>タグの中で<input type="file">を使えばいいでしょう。この<form>からアップロードされたファイルはBottleのrequest.files.get()メソッドを使って受け取ります。

前回紹介したように,BottleではHTTPのリクエストメソッドごとにルーティングを設定できるので,"/upload"をGETでアクセスすると<form>タグを送り,POSTならばファイルを受けとる,ということにすると,こんなコードが書けます。

15  @route('/upload', method="GET")
16  def upload_file():
17      return '''
18  upload photo
19  
20  <form action="/upload" method="POST" enctype="multipart/form-data">
21     <input type="file" name="img_file"> <P>
22     <input type="submit" value="アップロード">
23  </form>
24  '''
25  
26  @route('/upload', method="POST")
27  def get_file():
28      upload = request.files.get('img_file')
29      upload.save("./Photo/")
30      return 'Upload OK. FilePath: %s' % (upload.filename)

前半のupload_file()は,アップロード用の<form>タグを送る処理で,後半のget_file()が送られてきたファイルをPhoto/以下にセーブする処理です。20行目で指定しているenctype="multipart/form-data"は,送信するデータが複数のパートから構成されていることを示し,ファイルのアップロードの際には必須の指定になります。

後半の処理では,<form>経由で送られてくるデータを保持しているrequest.filesオブジェクトを,name属性で指定した'img_file'という名前をキーにuploadにコピーし,このオブジェクトが持つsaveメソッドを使って,指定したディレクトリ("./Photo/")以下に受け取ったデータをセーブしています。

28~29行目は,request.files.get('img_file').save("./Photo/") とまとめることも可能です。

このコードを先に紹介した画像表示用のスクリプトに追加して,"http://localhost:8080/upload/"にアクセスすると,upload_file()から送られたファイルアップロード用の画面(<form>タグ)が表示されます。この画面の"Browse…"ボタンを押すと,ブラウザ側の機能でサムネイル表示を有したファイル選択ウィンドウが開きます。

図6 ファイルアップロード用の選択ウィンドウ

図6 ファイルアップロード用の選択ウィンドウ

このウィンドウでファイルを選択し,⁠アップロード」ボタンを押すと,POSTメソッドでサーバにファイルが送信され,29行目のupload.save()で"./Photo/"ディレクトリにファイルがセーブされて,"Upload OK"のメッセージが返されます。

この後,http://localhost:8080/show にアクセスすると,新しくアップロードした画像もちゃんと表示されました。

図7 一覧リストの更新

図7 一覧リストの更新

今回のスクリプトの最終形は以下の通りで,30行ほどのコード(と10行弱のテンプレートファイル)で簡単なウェブアルバムが作成できました。

 1  #!/usr/bin/python
 2  
 3  import os
 4  from bottle import route, run, static_file, template, request
 5  
 6  @route('/show/<filename>')
 7  def server_static(filename):
 8      return static_file(filename, root='./Photo/')
 9  
10  @route('/show')
11  def list():
12      files = os.listdir('./Photo')
13      return(template('show_list', photos=files))
14  
15  @route('/upload', method="GET")
16  def upload_file():
17      return '''
18  upload photo
19  
20  <form action="/upload" method="POST" enctype="multipart/form-data">
21     <input type="file" name="img_file"> <P>
22     <input type="submit" value="アップロード">
23  </form>
24  '''
25  
26  @route('/upload', method="POST")
27  def get_file():
28      upload = request.files.get('img_file')
29      upload.save("./Photo/")
30      return 'Upload OK. FilePath: %s' % (upload.filename)
31  
32  run(host='localhost', port=8080, reloader=True, debug=True)

このスクリプトは必要最低限の機能を実装しただけで実用性は低いものの,Bottleの便利さと開発の簡単さは感じていただけたのではないでしょうか。


今回は画像ファイルをやりとりしたものの,Bottleのstatic_file()メソッドは画像ファイル専用ではなく,動画や音声ファイルでも適切なHTTPレスポンスヘッダを作成してくれます。

加えて,firefoxやchromeのようなブラウザは,さまざまな音声/動画CODECにネイティブで対応しているので,今回のコードを元に,マルチメディア・アルバムみたいなのも簡単に作れそうです。

このように,事前にあれこれ準備する手間なく,アイデアを簡単に試してみれるのがBottleの最大の魅力でしょう。

著者プロフィール

こじまみつひろ

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

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