web.pyでwebアプリを作ってみよう
はじめに
皆様、お疲れ様です。
この記事では、pythonで動作するwebフレームワークであるweb.pyを用いたアプリケーション開発の基礎的な部分について記述しています。
まず手始めに、web.pyの公式ページの説明を読んでみましょう。
web.py is a web framework for Python that is as simple as it is powerful. web.py is in the public domain, you can use it for whatever purpose with absolutely no restrictions.
- pythonで動くシンプルでパワフルなwebフレームワークだよ。
- パブリックドメインなので、制限なし・どんな理由であっても利用することができるよ。
...らしいです。なんだかワクワクしてきましたね。
それでは、インストールから始めましょう。今回参考にする資料はweb.pyの公式チュートリアル、およびCookbookです。
インストールしよう
私がweb.pyをはじめて触ったときはpython2にしか対応していなかったのですが、しばらく見ないうちにpython3にも対応していたようです。最新バージョンは0.61、pipを用いてインストールします。
$ pip install web.py==0.61
python2.7でサーバーを立てる場合は、バージョン0.51をインストールしましょう。0.51以後のバージョンはpython3でしか動作しないようです。
$ pip install web.py==0.51
サーバを記述しよう
インストールができたら、早速サーバを建てましょう。とりあえず、web.pyの便利機能が詰まっているweb
パッケージをインポートします。
import web
次に、URLのハンドリング(このURLにアクセスされたら、この処理をする、という対応関係)を定義していきましょう。今のところは、localhost:8080/
(ルート)にアクセスされたら、index
に記述された処理を実行するように設定をしておきましょう。
urls = (
"/", "index"
)
それでは、処理部分であるindex
をカッチリさせましょう。web.pyでは、URLに対応する処理をクラスとして記述します。先ほどルートに対応させたindex
を記述しましょう。
クラス内のGET
メソッドが、GETリクエストに対する処理が記述されている場所です。また、戻り値の内容がレスポンスの内容に対応します。以下のコードの場合、GETリクエストに対して、「Hello,world!」という文字列をレスポンスすることになります。
class index:
def GET(self):
return "Hello, world!"
最後に、サーバを建てるためのmainメソッドを書きましょう。web.application
メソッドの第2引数は、クラスのリスト(今回だったらindex
クラス)をサーバに登録するためにglobals()
になっています。
if __name__ == "__main__":
app = web.application(urls, globals())
app.run()
ここまでの作業が完了したら、app.py
の中身は以下のようになっているはずです。とりあえず、これだけでサーバは建ちます。
import web
urls = (
"/", "index"
)
class index:
def GET(self):
return "Hello, world!"
if __name__ == "__main__":
app = web.application(urls, globals())
app.run()
サーバを起動しよう
サーバも記述できたので、早速起動しましょう。コンソールに戻っていただいて、以下のように実行します。今回はpython3を使用することを想定しているので、python2で実行するときはpython2コマンドを使用してください。コマンドを実行すると、以下のように表示されます。
$ python3 app.py
http://0.0.0.0:8080/
ここまで完了したら、あとはこのURLにアクセスするだけです。アクセスしたら、ブラウザに「Hello,world!」と表示されます。
htmlファイルを表示させよう
ここまでで、単純な内容(文字列)をレスポンスするサーバが完成しました。しかし、これだけでは皆様が思い浮かべるアプリケーションとは呼べません。最低でも、あらかじめ用意したhtmlファイルを表示させたいですね。そこで、templates
ディレクトリに配置したindex.html
を、localhost:8080/
にアクセスしたときに表示させるように、サーバを改良していきましょう。ここからは、以下のディレクトリ構造を想定しています。
.
├─ templates
│ └─ index.html
└─ app.py
まずは、templates
ディレクトリをhtmlファイルの配置場所として登録しましょう。
render = web.template.render('templates/')
続いて、先ほどまで「Hello, world!」とレスポンスしていたところを、index.html
をレスポンスするように改良しましょう。
# GETメソッドのreturn文
return render.index()
ここで注意したいのは、登録したtemplates
ディレクトリ内のhtmlファイルが、web.template.render
のメソッドとして登録されていることです。今回の場合、index.html
から拡張子を抜いた名前であるindex
がメソッド名になります。
ここまで改良できたら、app.py
は以下のように記述されているはずです。
import web
render = web.template.render('templates/')
urls = (
"/", "index"
)
class index:
def GET(self):
return render.index()
if __name__ == "__main__":
app = web.application(urls, globals())
app.run()
早速、サーバを起動して動作を確認してみましょう。今回、index.html
は以下のように記述してみましょう。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Sample application</title>
</head>
<body>
HTMLファイルからHello, world!
</body>
</html>
localhost:8080/
にアクセスして、「HTMLファイルからHello, world!」と表示されれば成功です。
リダイレクトさせよう
ここまで、リクエストに対応するレスポンスを返すようにしていましたが、場合によってはリダイレクトしたいときもあると思います(ログイン履歴があったらマイページにリダイレクトとか)。そこで利用できるのがweb.seeother
メソッドです。それでは、localhost:8080/redirect
にアクセスしたらlocalhost:8080/
にリダイレクトするように改良しましょう。
まずは、/redirect
とクラスの対応関係をurls
に追加しましょう。今回は、/redirect
とredirect
クラスを対応させます。
urls = (
"/", "index",
"/redirect", "redirect" #ここを追加しました。
)
次に、redirect
クラスを記述しましょう。ここで注意したいのは、return
を用いてレスポンスするのではなく、raise
を用いて例外処理としてリダイレクトを実現するということです。
class redirect:
def GET(self):
raise web.seeother("/")
raise web.seeother("/")
は、クライアントに対してSee Other(HTTPステータス303)を返し、localhost:8080/
にリダイレクトするように命令しています。
ここまで改良できたら、app.py
は以下のように記述されているはずです。
import web
render = web.template.render('templates/')
urls = (
"/", "index",
"/redirect", "redirect"
)
class index:
def GET(self):
return render.index()
class redirect:
def GET(self):
raise web.seeother("/")
if __name__ == "__main__":
app = web.application(urls, globals())
app.run()
それでは、サーバを起動してlocalhost:8080/redirect
にアクセスしてみましょう。見かけ上はいきなりlocalhost:8080/
にアクセスしているように見えますが、開発者ツール(Chromeの場合F12で見ることができる画面)を用いると、localhost:8080/redirect
からlocalhost:8080/
にリダイレクトされていることがわかると思います。
静的ファイルを活用しよう
ここまでは、サーバとクライアントの間でやり取りされている情報は文字、具体的にはhtmlファイルでしたが、アプリケーションでは装飾用の画像や、様々な機能を付与するためのjavascript、ページの体裁を整えるためのcssなど(静的ファイル)を活用したい気持ちになります。しかし、適当にassets
ディレクトリを作成して、その中に静的ファイルを配置したとしても、localhost:8080/assets/hoge.png
で画像を表示することはできません。
.
├─ assets
│ └─ hoge.png
├─ templates
│ └─ index.html
└─ app.py
解決方法は簡単です。web.pyを用いたアプリケーションではstatic
という名前のディレクトリを作成し、その中に静的ファイルを配置する必要があります。static
ディレクトリ配下に配置された静的ファイルは、クライアント側でlocalhost:8080/static/hoge.png
のように活用することが可能です。
.
├─ static
│ └─ hoge.png
├─ templates
│ └─ index.html
└─ app.py
異なる機能を別のファイルに記述したい
ここまで、「HTMLファイルからHello, world!」と表示する機能を実現するサーバを記述してきましたが、実際のアプリケーションでは様々な機能を用意する必要があります。それら様々な機能を1つのpythonファイルで管理すると、不具合が起きた際のデバッグ作業が少々面倒になります。
例えば、アプリケーションに必要な100個の機能がすべてapp.py
の中に記述されていた場合、ある機能に不具合が起きた際にapp.py
の中から該当箇所を探す手間がかかります。また、app.py
がgitなどでバージョン管理されていると、該当箇所のデバッグが完了するまで他の機能の実装がストップするという問題につながります。このような問題を回避するために、アプリケーションに必要な機能を複数のpythonファイルに分散して実装したい気持ちになります。
ここからは、2つの機能を2つのpythonファイルに分割して実装し、アプリケーションを実現する方法を習得しましょう。ここで実装する2つの機能は以下の通りです。
- 「Hello! This is sub-application 1!」という文字列を表示する。
- 「Hello! This is sub-application 2!」という文字列を表示する。
それでは、機能1から実装していきましょう。簡単のため、文字列をそのままレスポンスするように実装していきます。
import web
urls = (
"", "redirect",
"/", "index"
)
class index:
def GET(self):
return "Hello! This is sub-application 1!"
class redirect:
def GET(self):
raise web.seeother("/")
subapp2 = web.application(urls, globals())
ここで注意したいのは、変数urls
に""
が登録されていることです。これが登録されていないと、例えばlocalhost:8080/subapp1
にアクセスした際に「そんなページはない」と怒られます。
続いて、機能1と同様に機能2を実装しましょう。
import web
urls = (
"", "redirect",
"/", "index"
)
class index:
def GET(self):
return "Hello! This is sub-application 2!"
class redirect:
def GET(self):
raise web.seeother("/")
subapp2 = web.application(urls, globals())
最後に、これら2つの機能を統合するためのintegration.py
を記述しましょう。ここまで記述してきたsubapp1.py
とsubapp2.py
をインポートし、変数urls
にURLのパターンと、それぞれのsubappで定義したweb.application
を登録しましょう。
import web
import subapp1 # 機能1をインポート
import subapp2 # 機能2をインポート
render = web.template.render('templates/')
urls = (
"/subapp1", subapp1.subapp1, # 機能1を登録
"/subapp2", subapp2.subapp2, # 機能2を登録
"/", "index",
"/redirect", "redirect"
)
class index:
def GET(self):
return render.index()
class redirect:
def GET(self):
raise web.seeother("/")
if __name__ == "__main__":
app = web.application(urls, globals())
app.run()
ここまで記述出来たら、以下のようにコマンドを実行してサーバを起動しましょう。
$ python3 integration.py
http://0.0.0.0:8080/
サーバの起動が完了したら、localhost:8080/subapp1/
とlocalhost:8080/subapp2/
にアクセスしてみましょう。想定した文字列が表示されていれば成功です。
さいごに
ここまでで、web.pyを用いたwebアプリケーション作成の基礎的な部分を説明してきました。web.py特有の表現方法は随所にあらわれましたが、案外記述しやすい文法になっているのかなぁと思います。今回扱った内容のほかにも、PostgreDBと接続する方法だったり、電子メールを扱ったりする機能もあるみたいなので、興味のある方はCookbookを見ながら遊んでみると楽しいと思います。また、時間ができたときにこの記事の内容を拡張できたらいいなと思っています。
こんなところで、今回の記事を終わりにします。ここまで読んでいただきありがとうございました。
Discussion