2011年06月06日

GAE/Pでリクエストデータの扱い方。

GAE for Pythonでリクエストデータの扱い方を簡単に紹介する。
以下は受け取ったリクエストデータをそのままクライアントへ帰すだけのシンプルなものだ。

まずは画面HTMLだ。

index.html
<html>
<head>
<meta content='text/html; charset=UTF-8' http-equiv='Content-Type'/>
</head>
<body>
<form method="get" action="/">
名前:<input type="text" name="name" />
<br/>
性別:<input type="radio" name="sex" value="男性" />男性
<input type="radio" name="sex" value="女性" />女性
<br/>
好きな果物:<select name="fruits" multiple="true">
<option value="りんご">りんご</option>
<option value="みかん">みかん</option>
<option value="いちご">いちご</option>
</select>
<br/>
送信に同意:<input type="checkbox" name="agree" value="はい" /><br/>
<input type="submit" value="送信" />
</form>

<p>結果</p>
名前:<b>{{ name }}</b><br/>
性別:<b>{{ sex }}</b><br/>
好きな果物:
{% for fruit in fruits %}
<b>{{ fruit }}</b>,
{% endfor %}<br/>
同意:<b>{{ agree }}</b>
</body>
</html>


次にお馴染みの helloworld.py だ。

helloworld.py
# -*- coding: utf-8 -*-
import cgi
import os

from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext.webapp import template
import logging

#
# メインハンドラ
#
class MainHandler(webapp.RequestHandler):
def get(self):
# <input name="name" type="text" />
name = self.request.get("name")
logging.info("name:" + name)

# <input name="sex" type="radio" />
sex = self.request.get("sex")
logging.info("sex:" + sex)

# <select name="fruits" multiple>...</select>
fruits = self.request.get("fruits", allow_multiple=True)
for fruit in fruits:
logging.info("fruits:" + fruit)

# <input name="agree" type="checkbox" />
agree = self.request.get("agree", default_value="いいえ")
logging.info("agree:" + agree)

template_values = {
"name" : name,
"sex" : sex,
"fruits" : fruits,
"agree": agree
}
path = os.path.join(os.path.dirname(__file__), 'index.html')
self.response.out.write(template.render(path, template_values))


application = webapp.WSGIApplication([('/', MainHandler)],
debug=True)

def main():
run_wsgi_app(application)

if __name__ == "__main__":
main()


以上である。

ここはひとつポチっとよろしく。
人気ブログランキングへ

プログラミング Google App Engine
Dan Sanderson
オライリージャパン
売り上げランキング: 40082



posted by 寄り道退屈男 at 08:43 | Comment(0) | TrackBack(0) | GAE for Python

2011年06月03日

GAE/PでCRONを使ったスケジュールタスク実行。

GAE for Python では、CRONジョブでスケジュールタスクを実行できる。

参考

まず、cron.yaml というファイルを新規作成し、app.yamlなどと同じ場所に保存する。

cron.yaml
cron:
- description: execute every 24 hours.
url: /hogetask
schedule: every 24 hours
timezone: Asia/Tokyo
- description: execute at 23:00 everyday.
url: /footask
schedule: every day 23:00
timezone: Asia/Tokyo
- description: execute at 9:00 every monday.
url: /baatask
schedule: every monday of month 09:00
timezone: Asia/Tokyo

ざっと説明すると、description: はコメント、url: は実行するタスクのURL、そして、schedule: はスケジュール・フォーマットを表し、実行する日時やタイミング(スケジュール)を指定する。スケジュール・フォーマットの詳細はこちらを参照のこと。

そして、お馴染みの app.yaml は以下のように記述する。

app.yaml
application: hello-cron
version: 1
runtime: python
api_version: 1

handlers:
- url: /hogetask
script: hogetask.py
login: admin
- url: /footask
script: footask.py
login: admin
- url: /baatask
script: baatask.py
login: admin

特に説明の必要は無いだろう。
大切なのは login: admin の部分だ。
こう記述しておけば、たとえ外部からタスクのURLにアクセスされても管理者でなければジョブが実行されることはない。

後は appcfg.py を利用してGAEアプリをアップロードすればCRONジョブは設定される。

アップロードしたCRONジョブを初期化したい場合は、cron.yaml に以下の内容のみを記述してアップロードすれば良い。
cron.yaml
cron:


なお、ローカル開発環境のCRONジョブは、 http://localhost:8080/_ah/admin/cron へアクセスすると確認できる。



ここはひとつポチっとよろしく。
人気ブログランキングへ

プログラミング Google App Engine
Dan Sanderson
オライリージャパン
売り上げランキング: 40082



posted by 寄り道退屈男 at 15:13 | Comment(0) | TrackBack(0) | GAE for Python

2011年06月01日

GAE/PでModelをJSON変換する方法。

以前に GAE for Python でJSONなデータのAJAX通信のやり方を紹介した。

今回はもう少しだけステップアップして、GAEのModelをJSON変換する方法を紹介したいと思う。まだデータストアの基本を押さえていない人は先にこちらで使い方を学んで欲しい。

さて、始めようか。

以下のサンプルは、画面からメッセージを投稿すると、サーバでGAEのデータストアへ登録されると同時にデータストアからメッセージ一覧を取得してJSON形式へ変換し、クライアント(ブラウザ)へ返すというものである。

まず重要となってくるのは、モデルをJSON形式にシリアライズための処理だ。
今回はjson.pyというクラスを利用させて貰った。その中身は以下の通りだ。
json.py
# -*- coding: utf-8 -*-
"""Utility classes and methods for use with simplejson and appengine.

Provides both a specialized simplejson encoder, GqlEncoder, designed to simplify
encoding directly from GQL results to JSON. A helper function, encode, is also
provided to further simplify usage.

GqlEncoder: Adds support for GQL results and properties to simplejson.
encode(input): Direct method to encode GQL objects as JSON.
"""

import datetime
import simplejson
import time

from google.appengine.api import users
from google.appengine.ext import db


class GqlEncoder(simplejson.JSONEncoder):

"""Extends JSONEncoder to add support for GQL results and properties.

Adds support to simplejson JSONEncoders for GQL results and properties by
overriding JSONEncoder's default method.
"""

# TODO Improve coverage for all of App Engine's Property types.

def default(self, obj):

"""Tests the input object, obj, to encode as JSON."""

if hasattr(obj, '__json__'):
return getattr(obj, '__json__')()

if isinstance(obj, db.GqlQuery):
return list(obj)

elif isinstance(obj, db.Model):
properties = obj.properties().items()
output = {}
for field, value in properties:
output[field] = getattr(obj, field)
return output

elif isinstance(obj, datetime.datetime):
output = {}
fields = ['day', 'hour', 'microsecond', 'minute', 'month', 'second',
'year']
methods = ['ctime', 'isocalendar', 'isoformat', 'isoweekday',
'timetuple']
for field in fields:
output[field] = getattr(obj, field)
for method in methods:
output[method] = getattr(obj, method)()
output['epoch'] = time.mktime(obj.timetuple())
return output

elif isinstance(obj, time.struct_time):
return list(obj)

elif isinstance(obj, users.User):
output = {}
methods = ['nickname', 'email', 'auth_domain']
for method in methods:
output[method] = getattr(obj, method)()
return output

return simplejson.JSONEncoder.default(self, obj)


def encode(input):
"""Encode an input GQL object as JSON

Args:
input: A GQL object or DB property.

Returns:
A JSON string based on the input object.

Raises:
TypeError: Typically occurs when an input object contains an unsupported
type.
"""
return GqlEncoder().encode(input)


次にお馴染みの helloworld.py だ。
helloworld.py
# -*- coding: utf-8 -*-
import cgi
import os

# json.py をインポート
import json

from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext.webapp import template
from google.appengine.ext import db
from django.utils import simplejson
import logging

#
# メッセージモデル
#
class Message(db.Model):
content = db.StringProperty(multiline=True)
date = db.DateTimeProperty(auto_now_add=True)

#
# メインハンドラ
#
class MainHandler(webapp.RequestHandler):
def get(self):
template_values = {}
path = os.path.join(os.path.dirname(__file__), 'index.html')
self.response.out.write(template.render(path, template_values))

#
# メッセージ一覧をJSONで返すハンドラ
#
class OutputJSON(webapp.RequestHandler):
def get(self):
# メッセージをデータストアへ登録
message = Message()
message.content = self.request.get('content')
message.put()
# データストアから最新10件のメッセージ一覧を取得
query = Message.all().order('-date')
results = query.fetch(10)
# メッセージ一覧をJSON変換してクライアントへ返す
json_results = json.encode(results)
self.response.out.write(cgi.escape(unicode(json_results, 'UTF-8')))


application = webapp.WSGIApplication([('/', MainHandler),
('/OutputJSON', OutputJSON)],
debug=True)

def main():
run_wsgi_app(application)

if __name__ == "__main__":
main()


そして、画面HTMLは以下の通り。
index.html
<html>
<head>
<meta content='text/html; charset=UTF-8' http-equiv='Content-Type'/>
<title>GAE/P+jQueryでJSONをAJAX(ModelをJSONへ変換編)</title>
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script>
$(function() {

$("#btn").click(function() {
// JSONレスポンスを返すURL
url = "http://localhost:8080/OutputJSON";
// リクエストパラメータ作成
req = {
"content" : $("#content").val(),
"callback" : "?" /* 他ドメインにリクエストする場合には必要 */
};
// AJAX
$.getJSON(url, req, callback);
});

/* コールバック関数 */
var callback = function(json){
$("#res").text("");
$.each(json, function(i, item) {
message = '投稿日時: '
+ formatDate(new Date(this.date['isoformat']))
+ '<br/>コメント: ' + this.content;
+ '<hr/>';
$("#res").append($('<p/>').html(message));
});
};

// UTC → JST
function utc2jst(utc) {
// JST = UTC + 9H
return new Date(utc.getTime() + 9*60*60*1000);
}

function formatDate(date) {
// GAEでは日付をUTCで保持しているのでJSTへ変換する
jst = utc2jst(date);

year = jst.getYear();
month = jst.getMonth() + 1;
day = jst.getDate();
hour = jst.getHours();
minute = jst.getMinutes();
second = jst.getSeconds();
if (year < 2000) { year += 1900; }
if (month < 10) { month = '0'+month; }
if (day < 10) { day = '0'+day; }
if (hour < 10) { hour = '0'+hour; }
if (minute < 10) { minute = '0'+minute; }
if (second < 10) { second = '0'+second; }
return String(year)
+ '/'
+ month + '/'
+ day + ' '
+ hour + ':'
+ minute + ':'
+ second;
}


});
</script>
</head>
<body>
<p>リクエスト</p>
<textarea name="content" id="content"></textarea>
<button id="btn">送信</button>
<p>レスポンス</p>
<div id="res"></div>
</body>
</html>


重要となる Model から JSON への変換、以下の部分だ。
変数resultsは、Messageモデルのリストである。
json_results = json.encode(results)


それ以外で重要なところというと、index.html でJavascriptを使って日付を UST から JST(日本時間) へ変換しているところくらいかな。
GAEでは日付をUSTで保持しているので注意が必要だ。
ちなみに UST+9時間 が JST となる。
formatDate(new Date(this.date['isoformat']))

  // UTC → JST
function utc2jst(utc) {
// JST = UTC + 9H
return new Date(utc.getTime() + 9*60*60*1000);
}

function formatDate(date) {
// GAEでは日付をUTCで保持しているのでJSTへ変換する
jst = utc2jst(date);

year = jst.getYear();
month = jst.getMonth() + 1;
day = jst.getDate();
hour = jst.getHours();
minute = jst.getMinutes();
second = jst.getSeconds();
if (year < 2000) { year += 1900; }
if (month < 10) { month = '0'+month; }
if (day < 10) { day = '0'+day; }
if (hour < 10) { hour = '0'+hour; }
if (minute < 10) { minute = '0'+minute; }
if (second < 10) { second = '0'+second; }
return String(year)
+ '/'
+ month + '/'
+ day + ' '
+ hour + ':'
+ minute + ':'
+ second;
}


以上だ。


ここはひとつポチっとよろしく。
人気ブログランキングへ


プログラミング Google App Engine
Dan Sanderson
オライリージャパン
売り上げランキング: 92707

posted by 寄り道退屈男 at 11:49 | Comment(0) | TrackBack(0) | GAE for Python

2011年05月31日

GAE/P向け統合開発環境 Eclipse PyDev。

GAE for Python で開発する場合でも、やっぱり便利なIDE(統合開発環境)を使いたいことだろう。

そこで今回は、Javaエンジニアにはお馴染みの Eclipse を GAE for Python 用にカスタマイズする方法を紹介する。

PythonやGAEのSDKは既にインストール済みという前提で書いていくので、まだの人はこちらを参考にして環境を整えてくれ。

では、始めようか。
まず、Eclipse本体をインストールする。
既にパソコンへインストールされている人は読み飛ばして結構だが、未だの人は以下から落としてくるといいだろう。
以下は Pleiades と言って便利なプラグインを予めインストールしてあるEclipseの日本語ディストリビューションだ。

日本語 Eclipse / Pleiades All in One

Eclipseのバージョンとインストール済みプラグインにより選択肢は何種類かあるが、取り敢えず俺はソコソコ軽そうでホドホドに枯れたバージョンである Eclipse 3.5.2 Galileo - Platform - Full All in One (JRE あり) をダウンロードしてみた。

さて、Eclipseのインストール(といっても解凍するだけだが)が完了したら、次はEclipse用Pythonプラグイン PyDev をインストールする。

まず、Eclipseを起動し、メニューから「ヘルプ」-「新規ソフトウェアのインストール」を選択する。

"インストール" という画面が開くので、"追加" ボタンを押す。

次の画面で、"名前" に PyDev、"ロケーション" に http://pydev.org/updates/ と入力し、OKボタンを押す。

"作業対象" から PyDev - http://pydev.org/updates/ を選択し、PyDev チェックボックスにチェックを入れ、"次へ" ボタンを押す。
以降は後は画面に従ってインストールすれば良い。


■PyDev Google App Engine Project の作成

PyDevのインストールが終わったら、早速GAE用プロジェクトを作成してみよう。

まず、メニューから「ファイル」-「新規」-「その他」を選択。
PyDev フォルダアイコン内の PyDev Google App Engine Project を選択し、"次へ" ボタンを押す。

次の画面で、「Please configure an interpreter in the related preferences before proceeding.(リストされていないインタープリターを構成するにはここをクリックしてください。)」の文字リンクをクリック、"Python インタープリター" パネルで "新規" ボタンを押す。

自分のマシンにインストールされている Python インタープリターを選択。例えば "C:\Python27\python.exe" みたいな感じで。そして、OKボタンを押す。
次の画面でもOKボタンを押すと、PyDevプロジェクト作成画面に戻るので、そこでプロジェクト名を入れて、先程選んだインタープリターを指定して、OKボタンを押す。

次の画面で Google App Engine のインストール先を指定する。例えば "C:\Program Files (x86)\Google\google_appengine" な感じで。GAE系ライブラリがずらりと出てきたらOKボタンを押す。

以上で PyDev のプロジェクトが完成したはずだ。


■Eclipse でのデバッグ方法
新しく出来た PyDev プロジェクトの src フォルダを右クリックし、「デバッグの構成」を選択。

"メイン" タブの "メイン・モジュール" の入力ボックスに自分のGAE環境の dev_appserver.py のパスを入力する。例えば、"C:\Program Files\Google\google_appengine\dev_appserver.py" みたいな感じで。

次に "引数" タブの "プログラムの引数" というテキストエリアに ${project_loc}/src と入力。
※メールの送信を行う場合は、引数に ${project_loc}/src -enable_sendmail と入力する。

最後に "インタープリター" タブの "インタープリター" の入力コンボボックスに先程設定したPythonインタープリターを選択。例えば "C:\Python27\python.exe" みたいな感じで。そして適用ボタンを押す。

以上でデバッグ実行が可能となる。


シンプルなプロジェクトなら Eclipse+PyDev を使うよりも使い慣れたテキストエディタでやる方がサクサク開発できて良い場合もあるので、そこは場面に合わせて使いわけよう。




ここはひとつポチっとよろしく。
人気ブログランキングへ


プログラミング Google App Engine
Dan Sanderson
オライリージャパン
売り上げランキング: 92707

posted by 寄り道退屈男 at 09:40 | Comment(0) | TrackBack(0) | GAE for Python

2011年05月30日

GAE/PとjQueryでJSONデータを簡単にAjax。

GAE for Python と jQeury を利用して、JSONデータのAJAX通信を行ってみる。

下のサンプルは、サーバへブログ情報パラメータ(ブログ題名とリンクURL)を渡すと、サーバ側は受け取ったブログ情報をそのままJSON形式に変換してクライアント(ブラウザ)へ返すという単純なものだ。

helloworld.py
# -*- coding: utf-8 -*-
import cgi
import os

from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext.webapp import template


class MainHandler(webapp.RequestHandler):
def get(self):
template_values = {}
path = os.path.join(os.path.dirname(__file__), 'json_ajax.html')
self.response.out.write(template.render(path, template_values))


# 受け取ったリクエストパラメータ(ブログ情報)を
# そのままJSON文字列にして返すだけのリクエストハンドラ。
class OutputJSON(webapp.RequestHandler):
def get(self):
title = self.request.get('title').encode('UTF-8')
link = self.request.get('link').encode('UTF-8')
res = '{"title":"%s", "link":"%s"}' % (title, link)
self.response.out.write(cgi.escape(unicode(res, 'UTF-8')))

application = webapp.WSGIApplication([('/', MainHandler),
('/OutputJSON', OutputJSON)],
debug=True)

def main():
run_wsgi_app(application)

if __name__ == "__main__":
main()


json_ajax.html
<html>
<head>
<meta content='text/html; charset=UTF-8' http-equiv='Content-Type'/>
<title>GAE/P+jQueryでJSONをAJAXしてみる</title>
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script>
$(function() {

$("#btn").click(function() {
// JSONレスポンスを返すURL
url = "http://localhost:8080/OutputJSON";
// リクエストパラメータ作成
req = {
"title":$("#title").val(),
"link":$("#link").val(),
"callback":"?" /* 他ドメインにリクエストする場合には必要 */
};
// AJAX
$.getJSON(url, req, callback);
});

/* コールバック関数 */
var callback = function(json){
message = '<a href="' + json.link + '">' + json.title + '</a>';
$('#res').html(message);
};
});
</script>
</head>
<body>
<p>リクエスト</p>
<input type="text" id="title" value="俺の砂箱" /><br/>
<input type="text" id="link" value="http://sunabako.sblo.jp" /><br/>
<button id="btn">送信</button>
<p>レスポンス</p>
<div id="res"></div>
</body>
</html>


ちなみに、GAEのSDKにも便利なJSON系ライブラリ django.utils.simplejson が標準装備されていて、場合によってはそちらを利用してJSONデータの変換を行うほうが断然楽である。使い方を以下に示しておく。
from django.utils import simplejson

# JSON形式文字列をディクショナリ(連想配列)へ変換
dect = simplejson.loads(str)
# ディクショナリ(連想配列)をJSON形式文字列へ変換
str = simplejson.dumps(dect)



posted by 寄り道退屈男 at 13:38 | Comment(0) | TrackBack(0) | GAE for Python