‘GAE DAYS’ カテゴリーのアーカイブ

DAYS 14 Google Map との連動

2009年11月18日 水曜日

[ GAE Google App Engine ][ Phthon ][ Google Bigtable ][ Google Maps API ]
[ Google AJAX API ]
万歩計MAP(http://manpokeimap.appspot.com/)というものを作成した。
Google App EngineとGoogle Maps APIの連携できたらいいなぁ
と思っていたので、やってみた。
当初考えていたのは、
Google Maps APIでコースを作成して、
万歩計の歩数を入力していくことで、
自分が現在そのコースのスタート地点から
どこまで歩いたかがわかるというもの。
最近の万歩計は、
母を訪ねて三千里
日本一周」(日本一周歩数計の旅)
なんてものもあるので、
歩数と距離のみの単機能の私の万歩計でも
そんな遊びができるように願いを込めて作ろうと思ったのである。
サイトを見て、おわかりの通り、
そんな簡単に行くわけがない。
力尽きた結果、なんとか
ここ 
まできた。
Code Playground

http://code.google.com/apis/ajax/playground/

というものがあり、
これを使えば、Javascriptオンリーで、
(GAEなんぞ連携しないでも)
自分のホームページにGoogle Mapsを表示することができる。
今回のアプリケーションを作成する上でのポイントは、
GAEのGoogle Bigtableに、
Google Mapsの情報を保存することである。
ただ簡単なものだと、
「わざわざそんなことをしなくてもよい」となるので
小難しいことに挑戦した。
(できる人がやれば、簡単で必要のないものかもしれないが・・・)
方針としては、
http://code.google.com/apis/ajax/playground/#map_directions_advanced
をカスタマイズ
ルートを選択した後、
ルートのデータを保存する方法を考えることにした。
つづく。
私がつくったアプリ↓
協調型意思決定支援システム「○ 賛否両論 ×(ベータ版)」

http://sanpiryoron.appspot.com/

協調型プロジェクトタスク管理ツール「キャッチ&リリース(ベータ版)」

http://ctchandrls.appspot.com/

GoogleデータサービスAuthSub API利用サンプルアプリ
万歩計MAP

DAYS 13 Gdataとの連動

2009年11月5日 木曜日

[ GAE Google App Engine ][ Phthon ][ Google Bigtable ][ AuthSub API ]
GAEアプリケーションとGoogleデータサービスとの連動について考えてみた。
ドキュメント、写真、動画については、
GAEのアプリケーションと連動することでどれだけのメリットがあるだろうか?
いろいろ考えたが、それぞれのアプリ側(GAEでない側)で
「共有」の設定をしてしまえば、事足りるのではないかと考えるようになった。
GAEでの作りこみの時間、コストを考えると、
人間側でルールを決め運用する方がパフォーマンスがよさそうである。
最初に、連動することによるメリットが高いと考えていたカレンダーと地図も
同じように「無理やり連動させることないんじゃなか?」と考えるようになり、
少しやる気をなくしている。
ただ、これは、私が、Googleデータサービスを使いきれていないからかもしれない。
もっと新しいことができるのに、古い考え方でそれを見逃しているのかもしれない。
私がつくったアプリ↓
協調型意思決定支援システム「○ 賛否両論 ×(ベータ版)」

http://sanpiryoron.appspot.com/

協調型プロジェクトタスク管理ツール「キャッチ&リリース(ベータ版)」

http://ctchandrls.appspot.com/

GoogleデータサービスAuthSub API利用サンプルアプリ

DAYS 12 AuthSub API

2009年11月4日 水曜日

[ GAE Google App Engine ][ Phthon ][ Google Bigtable ][ AuthSub API ]
GoogleデータサービスAuthSub API利用サンプルアプリ
GAEから利用できるGoogleデータサービスを使ってみた。
本来であれば、アプリケーションに絡めて連動するような形にしたかったが、
連動のさせ方がよくわからず、とりあえず、 「 AuthSub API 」を使って
認証をし、各Googleデータサービスのデータ一覧をとってくるというアプリを作成した。
何度も繰り返すが、本来であれば、協調型プロジェクトタスク管理ツール「キャッチ&リリース(ベータ版)」

http://ctchandrls.appspot.com/の締切日をGoogleカレンダーに連動させたかったのだが、

どうにも動かせない。
できたのは、一覧をとってくることぐらいだったのだ。
Google Data サービスの使用」オンラインマニュアルを参考にしたが、
最終的には、自分のやり方になってしまったように思う。
もしかしたら、これが原因で、「書き込み・更新・削除」の処理ができないのかもしれない。
オンラインマニュアルでは、以下のAPIが提供されていると書かれているが、
Google Data Python モジュールのバージョンがあがっているらしく、
ダウンロードサイトでは他のAPIについても書かれている。
ただ、GAEで利用できるものとは違うのかもしれない。
* 認証
* Google Base
* カレンダー
* 連絡先
* ドキュメント
* Picasa ウェブ アルバム
* スプレッドシート
* YouTube
その中で、私の作ったサンプルアプリでは、
5つのサービスの一覧をとってこれるようにした。
*GoogoleDocs
*GoogleCalender
*Picasa Web アルバム
*YouTube
*GoogleSpreadSheets
利用する前に気をつける点
・いうまでもないが、各サービスの利用を開始していなければ、アクセスはできない。
・YouTubeのみ、「マイ動画」一覧ではなく、「再生回数の多い動画」一覧をとってきている。
なぜならば、「マイ動画」一覧のデータにアクセスするには、Developer Registrationが必要で、私は登録していないからである。
処理のプロセスとしては、2ステップある。
最初のページを表示する際に、
トークンをリクエストするリンクを作成する。
リンクをクリックすると
Googleアカウントの「アクセス要求」に移り、
「アクセスを許可」することで、トークンが手に入る。
次のページを表示する際に、
トークンをアップグレードし、データを取得し、
一覧を表示する。
main.pyの抜粋を以下に記す。

<pre>~~~~~~省略~~~~~~~
class MainHandler(webapp.RequestHandler):
layout_file ='layout.html'
view_dir = '../views/'
layout = {
'title':'Googleデータアクセス',
'body_title':'Googleデータアクセス',
'heder_title':'',
'heder_content':'',
'header':'header.html',
'footer':'footer.html',
}
def get(self):
user = users.get_current_user()
if user:
self.layout['link'] = ("ようこそ、%s! (<a href="\">ログアウト</a>)" %
(user.nickname(), users.create_logout_url(self.request.uri)))
else:
self.layout['link'] = ("<a href="\">ログイン</a>." %
users.create_login_url(self.request.uri))
client = gdata.service.GDataService()
gdata.alt.appengine.run_on_appengine(client)
#
docs_gdataScope = 'http://docs.google.com/feeds/'
authsub_docs = atom.url.Url('http', settings.HOST_NAME, path='/docs')
gdurl_docs = client.GenerateAuthSubURL(authsub_docs,docs_gdataScope,secure=False, session=True)
cal_gdataScope = 'http://www.google.com/calendar/feeds'
authsub_cal = atom.url.Url('http', settings.HOST_NAME, path='/calender')
gdurl_cal = client.GenerateAuthSubURL(authsub_cal,cal_gdataScope,secure=False, session=True)
pic_gdataScope = 'http://picasaweb.google.com/data/'
authsub_pic = atom.url.Url('http', settings.HOST_NAME, path='/picasa')
gdurl_pic = client.GenerateAuthSubURL(authsub_pic,pic_gdataScope,secure=False, session=True)
yt_gdataScope = 'http://gdata.youtube.com'
authsub_yt = atom.url.Url('http', settings.HOST_NAME, path='/youtube')
gdurl_yt = client.GenerateAuthSubURL(authsub_yt,yt_gdataScope,secure=False, session=True)
ss_gdataScope = 'http://spreadsheets.google.com/feeds/'
authsub_ss = atom.url.Url('http', settings.HOST_NAME, path='/spreadsheets')
gdurl_ss = client.GenerateAuthSubURL(authsub_ss,ss_gdataScope,secure=False, session=True)
self.layout['content'] = self.view_dir + 'index.html'
params = {'gdurl_docs':gdurl_docs,'gdurl_cal':gdurl_cal,'gdurl_pic':gdurl_pic,'gdurl_yt':gdurl_yt,'gdurl_ss':gdurl_ss,'user':user,'layout':self.layout}
fpath = os.path.join(os.path.dirname(__file__),'layouts',self.layout_file)
html = template.render(fpath,params)
self.response.out.write(html)
class DocsHandler(webapp.RequestHandler):
layout_file ='layout.html'
view_dir = '../views/'
layout = {
'title':'GoogleDocumentデータアクセス',
'body_title':'GoogleDocumentデータアクセス',
'heder_title':'',
'heder_content':'',
'header':'header.html',
'footer':'footer.html',
}
def get(self):
user = users.get_current_user()
client = gdata.docs.service.DocsService()
gdata.alt.appengine.run_on_appengine(client)
session_token = None
# Find the AuthSub token and upgrade it to a session token.
auth_token = gdata.auth.extract_auth_sub_token_from_url(self.request.uri)
if auth_token:
# Upgrade the single-use AuthSub token to a multi-use session token.
session_token = client.upgrade_to_session_token(auth_token)
if session_token and users.get_current_user():
# If there is a current user, store the token in the datastore and
# associate it with the current user. Since we told the client to
# run_on_appengine, the add_token call will automatically store the
# session token if there is a current_user.
client.token_store.add_token(session_token)
elif session_token:
# Since there is no current user, we will put the session token
# in a property of the client. We will not store the token in the
# datastore, since we wouldn't know which user it belongs to.
# Since a new client object is created with each get call, we don't
# need to worry about the anonymous token being used by other users.
client.current_token = session_token
feed = client.GetDocumentListFeed()
self.layout['content'] = self.view_dir + 'gddocs.html'
params = {'feed':feed,'user':user,'layout':self.layout}
fpath = os.path.join(os.path.dirname(__file__),'layouts',self.layout_file)
html = template.render(fpath,params)
self.response.out.write(html)
~~~~~~省略~~~~~~~

以上。
私がつくったアプリ↓
協調型意思決定支援システム「○ 賛否両論 ×(ベータ版)」

http://sanpiryoron.appspot.com/

協調型プロジェクトタスク管理ツール「キャッチ&リリース(ベータ版)」

http://ctchandrls.appspot.com/

GoogleデータサービスAuthSub API利用サンプルアプリ

DAYS 11 日時に関して

2009年10月27日 火曜日

[ GAE Google App Engine ][ Phthon ][ Google Bigtable ]
日時のデータに関していくつか。
・タイムゾーンについて
db.modelの日時に関するプロパティで
「auto_now_add=True」「auto_now=True」を設定すると
すべて世界協定時刻(UTC)が保存される。
「キャッチ&リリース(ベータ版)」では、「締切」を入力するようになっているため、
日本時間の締切を入力するのが当り前であるが、
更新日時、登録日時は世界協定時刻(UTC)なのである。
この違いの解決方法としては、
データはすべて世界協定時刻(UTC)で保存し、
表示するときに、日本であれば、日本標準時(JST; GMT+09:00)表示に
変換するというのが正しいやり方のようだ。
ちなみに、入力した日時は、世界協定時刻(UTC)に変換しなければならない。
参考:はしっこの、そのへん「Google App Engine再び」
今回のシステムでは、変換は行っていない。
なぜなら、今後、世界規模でプロジェクトを実行することは容易に想定できるからである。それであれば、日時の基準を世界にひとつにした方がよい。
このシステムはWebである以上、日本時間が基準とはいえないのだから。
(日本語で作ってはありますが・・・)
日本にいる人間は、「現在の時間 プラス 9時間」という前提で、締切を決めたり、
作業を行えばよいのである。人間側で対応すべき問題である。
データの登録、更新処理の全ての処理に
この変換をいれるのが大変だから、と理由では断じてない!
・日時の整合性について
「締切日が現在より、未来であること」
「開始日と、完了日がひっくりかえらないこと」
といったチェック機能を入れようとしたが、やめた。
チェックは人間がする。そして、間違いに気づいたら人間が直す。
・日時の表示の変更について
HTMLページで、DateTimeデータを表示させると
「 2009-10-14 14:00:18.156817 」
のようにわけのわからない数字が、最後に入ってしまう。
表示形式の指定方法を変更するには、以下のようにする。
変更前「 2009-10-14 14:00:18.156817 」
{{ data.add_date}} と指定
変更後「 2009-10-14 14:00:18 」
{{ data.add_date|date:”Y-m-d H:m:s” }} と指定
私がつくったアプリ↓
協調型意思決定支援システム「○ 賛否両論 ×(ベータ版)」

http://sanpiryoron.appspot.com/

協調型プロジェクトタスク管理ツール「キャッチ&リリース(ベータ版)」

http://ctchandrls.appspot.com/

DAYS 10 俺はなんてアフォーム(FORM)なんだ!

2009年10月26日 月曜日

データの追加、編集処理、HTMLでいうFormの画面で、いくつか分かったことがあるので以下に記す。
前回の「○ 賛否両論 ×(ベータ版)」では、
唯一のデータ編集画面「ユーザー情報の編集」で、
編集のHTMLのFORM画面に、更新前のデータを表示させることができなかった。
表示させても、submitするとデータが追加されてしまい更新処理ができてなかった。
泣く泣く、Djangoを使わず処理した。
DjangoがGAEバージョンなので、あきらめていた。
だが、今回、試行錯誤した結果、Django使って、更新処理を行う方法が分かった。
本来、分かって当たり前なのかもしれないが、
やっと・・・
やっとわかった!
こんなかんじ↓↓↓

# モデルクラス
class UserData(db.Model):
user = db.UserProperty(required=True,auto_current_user=True)
name = db.StringProperty(required=True,verbose_name='※名前')
presentation = db.TextProperty(verbose_name='自己紹介')
del_flg = db.IntegerProperty(default=0,verbose_name='削除フラグ')
add_date = db.DateTimeProperty(auto_now_add=True,verbose_name='作成日時')
update_date = db.DateTimeProperty(auto_now=True,verbose_name='更新日時')
def __unicode__(self):
return self.name
# DjangoFormを使うためのフォームクラス
class UsrForm(djangoforms.ModelForm):
class Meta:
model = UserData
exclude = ['user','del_flg']
# ハンドラー
class UsrEditHandler(webapp.RequestHandler):
~~~(省略)~~~
def post(self):
user = users.get_current_user()
if user:
q = db.GqlQuery("SELECT * FROM UserData WHERE del_flg = 0 AND user = :1", user)
q = q.get()
<span style="color: #ff0000;">ここ!</span>
form = UsrForm(<span style="color: #ff0000;">instance=q</span>,data=self.request.POST)
if form.is_valid():
data = form.save()
data.put()
self.redirect('/user')
~~~(省略)~~~

そのほかには、
データ更新画面で入力ミスをした時のパラメータ受け渡しを完全に忘れていた。
たとえば、
「 http://ctchandrls.appspot.com/—-/—?id=XXXXX 」
のように、GETで「id」パラメータを渡している時は、
入力ミスをして、更新画面に戻った時にも、「id」パラメータを渡しておかないと
エラーになってしまう。
テストしたときに気づけばいいのだが、
入力ミスのテストは、少ししかやってないし、
やる気もあまりなく、公開直前に気付いた。
以上。
私がつくったアプリ↓
協調型意思決定支援システム「○ 賛否両論 ×(ベータ版)」

http://sanpiryoron.appspot.com/

協調型プロジェクトタスク管理ツール「キャッチ&リリース(ベータ版)」

http://ctchandrls.appspot.com/