[Dd]enzow(ill)? with DB and Python

DBとか資格とかPythonとかの話をつらつらと

Pythonで一番小さいWEBフレームワークbottle.py その3(GET,POST)

前回はBottleのルーティングについてまとめました。

今回もルーティングに関わりますが、HTTPのリクエストメソッドとBottleでの使い方についてまとめていきます。

HTTPリクエストメソッド

HTTPプロトコルにはいくつかのリクエストメソッドが用途毎に定義されています。

  • GET
  • POST
  • PUT
  • DELETE..

普通にブラウザで動くシンプルなWEBアプリを作る場合、GET/POSTを最低限使うことになります。

POSTを使うケースは、主にフォーム等の入力を受け取る場合です。例えばログイン画面や掲示板への投稿画面で入力された内容を受け取る場合はPOSTでアクセスをさせます。

bottleでのリクエストメソッド対応

bottleは@routeデコレータを使った場合、デフォルトではGETメソッドのアクセスへの割当を指定されたものとして動きます。

# GETで/にアクセスされた時にmethod_testを実行する
@route("/")
def method_test():
    return template('<b>Hello World</b>!')

POST等、他のメソッドに対応させる場合はrouteデコレータにmethodオプションを渡すか、メソッド名に対応したデコレータを使います。

  • @routeの場合
# POSTで/にアクセスされた時にmethod_testを実行する
@route("/", method="POST")
def method_test():
    return template('<b>Hello World</b>!')
  • @postの場合
from bottle import run, template, post
:
# POSTで/にアクセスされた時にmethod_testを実行する
@post("/")
def method_test():
    return template('<b>Hello World</b>!')
    

実際に使ってみる

マニュアルのコードを元に修正した以下のコードを動かしてみます。

# coding:utf-8
from bottle import run, get, post, template, request # or route


def check_login(username, password):
    """
    ログイン判定を行う。
    今回はダミー関数として、パスワードがdenzowならログインOKとする
    実際はユーザデータと照合等をする
    """
    if password == "denzow":
        return True
    else:
        return False

@get('/login') # or @route('/login')
def login():
    """
    GETで/loginにアクセスした際の処理
    """
    return '''
        <form action="/login" method="post">
            Username: <input name="username" type="text" />
            Password: <input name="password" type="password" />
            <input value="Login" type="submit" />
        </form>
    '''

@post('/login') # or @route('/login', method='POST')
def do_login():
    """
    POSTで/loginにアクセスした際の処理
    """
    # フォームからPOSTされたデータを取得する
    username = request.forms.get('username')
    password = request.forms.get('password')
    # ログイン判定を行う
    if check_login(username, password):
        return template("<p>Your login information was correct. welcome {{username}}</p>", username=username)
    else:
        return "<p>Login failed.</p>"


if __name__ == "__main__":
    # テスト用のサーバをlocalhost:8080で起動する
    # reloader=Trueにより、ソースを書き換えると自動的に再起動される
    run(host='localhost', port=8080, reloader=True)

起動して以下のURLにアクセスするとログイン画面が表示されます。

http://localhost:8080/login

今回のサンプルでは、パスワードをdenzowにすればどんなユーザ名でもログインできるダミー処理になっています。

ユーザ名とパスワードにdenzowといれると以下の様な画面になり、ログインできたことがわかります。

Your login information was correct. welcome denzow

また、パスワードを誤った場合は以下の様なメッセージになります。

Login failed.

それでは少しソースを追っていきます。

まず、ブラウザで直接ページを開いた場合はGETアクセスになります。そのため@get('/login')デコレータが付与されているlogin()が実行され、画面上にformタグで作成されたログインフォームが表示されます。

<form action="/login" method="post">
     Username: <input name="username" type="text" />
     Password: <input name="password" type="password" />
     <input value="Login" type="submit" />
</form>

このフォームはname=usernamename=passwordの2つの入力欄を持ちます。また入力され内容はformタグのactionに指定されているように/loginに送られます。自分自身に送っているように見えますがmethod='POST'があるのでブラウザで開いた場合とは異なりPOSTメソッドで/loginにアクセスします。

POSTで送信されますので、@post('/login')が付与されているdo_login()が実行されます。送信された内容は以下のようにrequest.forms.getより取得できます。

    # フォームからPOSTされたデータを取得する
    username = request.forms.get('username')
    password = request.forms.get('password')

getで指定する名前はformタグで用意した入力欄のname属性と一致しますのでココで入力されたそれぞれの値を取得できます。

あとは受け取った値をPython側で好きなように判定し、処理後の結果を戻してやればよいです。

まとめ

GETやPOSTなど、HTTPリクエストメソッドの基本的な部分とbottleでの使い方をまとめました。サンプルはログイン画面でしたが、formタグはWEBアプリの主要な要素であり、ログイン以外でも同じようなコードになりますので少しは参考になるかと思います。