SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

japan.internet.com翻訳記事

PythonとWSGIによるフォトギャラリーの作成

WSGIによるWebアプリケーションの作成

実装の解説

 では、この非常に単純なクラスを見ていきましょう。

class fsPicture(object):
   def __init__(self, root, template=base_template):
      self.template = template
      self.root = root

   def split_path_from_item(self, item):
      """removes the root directory from the path.
      This lets us use the result as a web path."""
      return "/" + item.replace(self.root, '')

   def directory_listing(self, directory, path):
      """returns html for a directory listing"""
      files = ""
      directories = ""
      for item in glob(directory + "/*"):
         web_path = self.split_path_from_item(item)
         if os.path.isdir(item):
            directories += """<div class="directory">
                           <a href="%s" class="directory">%s
                           </a></div>""" %
                          (web_path, web_path)
         elif os.path.isfile(item) and
            item.lower().endswith('.jpg'):
            files += """<div class="image">
            <img src="%s?thumbnail=200"><br/>
               <a href="%s">%s</a>
               </div>""" % (web_path, web_path, web_path)
      html = ""
      if directories:
         html += """<h2>Directories</h2>
            <div id="directories">%s</div>""" % directories
      if files:
          html +=  """<h2>Pictures</h2>
             <div id="pictures">%s</div>""" % files
      return html

   def picture(self, image, path):
      """returns raw binary image. If query string of "thumbnail"
      is passed to the app the image is resized to a maximum of
      the argument. For instance: /some_image.jpg?thumbnail=100"""
      i = Image.open(image)
      if self.query_string:
         try:
            size = cgi.parse_qs(self.query_string)
            size = size['thumbnail'][0]
            i.thumbnail((int(size), int(size)))
         except:
            pass
      s = StringIO()
      i.save(s, 'JPEG')
      return s.getvalue()

   def find_object(self, path):
      """finds the directory or picture referenced, returns the
      response and the mimetype"""
      item = os.path.join(self.root, *path.split('/'))
      if os.path.isdir(item):
         return ([self.template %
            self.directory_listing(item, path),], 'text/html')
      elif os.path.isfile(item) and item.lower().endswith('.jpg'):
         return ([self.picture(item, path),], 'image/jpeg')
      else:
            return ([self.template % 'not found'], 'text/html')

   def __call__(self, environ, start_response):
      """the entry point to the application"""
      self.query_string = environ.get('QUERY_STRING', False)
      response, mimetype = self.find_object(environ['PATH_INFO'])
      start_response('200 OK', [('content-type',mimetype)])
      return response

 __call__はWSGIサーバーが呼び出すメインエントリポイントです。__call__は、WSGI呼び出し可能関数のように引数としてenvironstart_responseをとり、オブジェクト必須のself引数もとります。また、オブジェクトプロパティquery_stringenvironQUERY_STRING値に設定しますが、これはURL内の?の後ろに続くすべてのものです。後でこれを使用して、写真のサイズを変更すべきかどうかを判断します。オブジェクトメソッドfind_objectの呼び出しから応答(バイナリJPEGまたはHTML)とMIME Typeを取得したら、そこにenviron変数PATH_INFOを渡します。これはURL内のドメインの後ろに続き、かつ?の前にあるすべてのものです。

 find_objectの役目は、PATH_INFOをファイルシステム上のオブジェクトに変換することです。この変換は実はオブジェクトの__init__メソッドの中で始まります。これがルートプロパティの設定されるところです。この場合、ルートとはファイルシステム上のベースディレクトリ(すべてのjpegを検索したい場所)のことです。また、引数としてテンプレートをとるか、上で宣言されたベーステンプレート(単に巨大な文字列)を使用します。find_objectが呼び出されると、Webパスとルートプロパティ(すべてのjpegが入っているファイルシステム上のディレクトリ)とを結合し、参照されたファイルがディレクトリかjpegかを判定します。

 そして、ファイルがディレクトリなら、directory_listingを呼び出して、ファイルシステム上のそのディレクトリとWebパスを渡し、そのディレクトリの内容をリストした大きなHTMLを取得します。ファイルがjpegなら、その呼び出しをpictureに引き渡します。pictureは"image/jpeg"というMIME Typeと、jpegからのraw jpegエンコードバイナリデータを返します。ユーザーがクエリ文字列 "thumbnail" を渡した場合は、指定の制約に合わせて実行時にイメージのサイズが変更されます。これにより、ディレクトリ内の各写真の小さなサムネールが得られます。

まとめ

 実際のところ、小さなWebアプリケーションを作成する場合以外は、DjangoPylonsといった既存のWebフレームワークを使用したほうがよいでしょう(この2つのフレームワークは、それ自体でWSGIアプリケーションとして機能します)。とはいえ、高レベルのフレームワークではなく、WSGIでアプリケーションを作成すれば、自分が選んだPython Webフレームワークで何が行われているのか知ることができます。

 本稿では、WSGIによるWebアプリケーションの作成に焦点を当て、WSGIミドルウェアには触れませんでした。WSGIミドルウェアでは、アプリケーションによるサーバー要求の処理の前または後にコードを挿入できます。WSGIで複雑なアプリケーションを本気で作成するつもりなら、Paste(Ian Bicking作の、一般的なWebパターンをクリーンなAPIでラップしたライブラリ集)とWebOb(やはりIan Bicking作の、Paste上に構築された最小限のフレームワーク)を検討してください。IanもWebObの使用例として、同じようなファイルサービングアプリケーションを書いています。

この記事は参考になりましたか?

連載通知を行うには会員登録(無料)が必要です。
既に会員の方はを行ってください。
japan.internet.com翻訳記事連載記事一覧

もっと読む

この記事の著者

japan.internet.com(ジャパンインターネットコム)

japan.internet.com は、1999年9月にオープンした、日本初のネットビジネス専門ニュースサイト。月間2億以上のページビューを誇る米国 Jupitermedia Corporation (Nasdaq: JUPM) のニュースサイト internet.comEarthWeb.com からの最新記事を日本語に翻訳して掲載するとともに、日本独自のネットビジネス関連記事やレポートを配信。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

Chris McAvoy(Chris McAvoy)

PSC Group LLC(イリノイ州シカゴ)の開発者。PythonおよびRubyのWebアプリケーションが専門。ブログはhttp://weblog.lonelylion.com

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/2396 2008/04/24 14:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー