データをAjax風にやり取りするように改造してみました

これまで書いてきたGAEのコードではブラウザからの入力データを受け取るたびにページを再描画する方法で画面を更新していましたが、今回ブラウザ側はJavascriptを使ってデータの送受信を行うように改造してみました。
ページ全体を描画するのは最初のアクセス時のみで以降はjQueryを使ってサーバとデータをやり取りし、ページ内の必要箇所のみを書き換えています。

ページの機能はcookieを用いたセッションを書いてみましたの記事のものと全く同じです。
新たに"/data"というURLに"POST"メソッドでデータを送信すると処理したデータを送り返すようにしています。

jQueryにはgetJSONというJSONを取得するためのメソッドもありますがgetJSONは"GET"メソッドでサーバにアクセスするため、取得した内容をブラウザがキャッシュしてしまいページをその都度更新するような用途にはむきません。
タイムスタンプをつけてキャッシュ対策する方法もあるようなのですが"POST"メソッドを使うほうが手軽です。("POST"メソッドで取得したデータはブラウザがキャッシュしません。)

最初に出力するHTML

<!DOCTYPE html>

<html lang="ja">
<head>
	<meta http-equiv="Content-Script-Type" content="text/javascript">
	<title>セッションテスト</title>
	<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js"></script>
	<script>
	var update = function(){
		var newUserName = $('#enter_name').val();
		var newWord = $('#enter_word').val();
		//サーバにリクエストを送る
		$.post('/data', {'newUserName': newUserName, 'newWord': newWord},
			function(data){
				//コールバック関数
				$('#username').html(data.username);
				var text = '';
				for(var i = 0; i < data.words.length; i++){
					text += ('<li>' + data.words[i] + '</li>');
				};
				$('#wordlist').html(text);
			}, 'json');
		
		$('#enter_name').val('');
		$('#enter_word').val('');
	};
	
	$(document).ready(update);
	</script>
</head>
<body>
	ようこそ<span id="username">GUEST</span>さん<br>
	これまでの入力は
	<ul id="wordlist">
		<li>未入力</li>
	</ul>
	<br>
	<form action="#">
	名前を入力する<br>
	<input type="text" id="enter_name"><br>
	単語<br>
	<input type="text" id="enter_word"><br>
	<input type="button" value="送信" onclick="update()">
	</form>
</body>
</html>

サーバ側コード

# coding: utf-8

import webapp2
import cgi
import os
import binascii
import jinja2
import json
from google.appengine.ext import db

jinja_environment = jinja2.Environment(
    loader=jinja2.FileSystemLoader(os.path.dirname(__file__)))


class UserProfile(db.Model):
    sessionID = db.StringProperty()
    name = db.StringProperty()
    words = db.StringListProperty()
    date = db.DateTimeProperty(auto_now_add=True)


class MainPage(webapp2.RequestHandler):
    def get(self):
        """セッションの作成とページの出力を行う
           ここでは用意されたページは送り出すだけであり動的な変更を加えない
        """
        sessionID = self.request.cookies.get('sessionID')

        if not sessionID:
            new_sessionID = binascii.hexlify(os.urandom(8))
            session = UserProfile(sessionID=new_sessionID)
            session.name = 'GUEST'
            session.words = []
            session.put()

        template = jinja_environment.get_template('sessiontest2.html')

        self.response.headers['Content-Type'] = 'text/html;charset=utf-8'

        if not sessionID:
            self.response.set_cookie('sessionID', new_sessionID, max_age=300)

        self.response.out.write(template.render())

    def post(self):
        self.get()


class JsonData(webapp2.RequestHandler):
    """ページのJavascriptからリクエストを受けてJSONを送る
    """
    @staticmethod
    def _session_check(sessionID):
        """
        セッションIDがすでにデータストアに登録されているか確認し
        Queryを返す
        """
        sessions = (UserProfile
                    .all()
                    .filter('sessionID =', sessionID)
                    )
        return sessions

    def post(self):
        """jQueryとデータをやりとりする"""
        sessionID = self.request.cookies.get('sessionID')

        if not sessionID:
            #セッションがない場合は例外
            raise Exception('Session Error')
            return

        session = self._session_check(sessionID)[0]
        session.name = (cgi.escape(self.request.get('newUserName')) or
                        session.name)

        if self.request.get('newWord'):
            session.words.append(cgi.escape(self.request.get('newWord')))

        session.put()

        json_to_send = {'username': session.name, 'words': session.words}

        self.response.headers['Content-Type'] = 'application/json'
        self.response.out.write(json.dumps(json_to_send))


app = webapp2.WSGIApplication([('/', MainPage), ('/data', JsonData)],
                              debug=True)