Google App Engine/Python関連のメモ
- kay-1.0.0 をリリースしました - Kays daddy
- http://blog.shehas.net/2010/07/13/kay-1-0-0
- Kay-Documentation
- KayドキュメントのPDF版。ローカルの環境でドキュメントを読むことができる。
- http://groups.google.com/group/kay-users/browse_thread/thread/f4f00863b82c586a
Google App EngineでQuery Cursorsを使ってみる。
「Google App EngineでQuery Cursorsを使ってみる。 « 山本隆の開発日誌」より。
Google App EngineでQuery Cursorsを使ってみる。
Google App EngineのQueryクラスのcursor機能を使うと、前回にfetchで取得したデータの続きを効率よく取得することが出来る。
使用するモデル
from google.appengine.ext import db
class Person(db.Model):
...
Personクラスには、positionの順に登録されている。
> q = Person.all().order('position')
> for p in q.fetch(5): print p.full_name
>
氏名0
氏名1
氏名2
氏名3
氏名4
続きのデータは次回に取得したい。
そこでカーソルを取得する。
> cursor = q.cursor()
memcacheにカーソルを記録しておく。(カーソルは文字列)
> from google.appengine.api import memcache
> memcache.set('person_cursor', cursor)
前回の続きからデータを取得しよう。
> r = Person.all().order('position')
memcacheに記録したカーソルを取り出し、Queryに設定する。
> cursor = memcache.get('person_cursor')
> r.with_cursor(cursor)
そうすると、前回にfetchした続きのデータを取得できる。
> for p in r.fetch(5): print p.full_name
>
氏名5
氏名6
氏名7
氏名8
氏名9
Google App Engineのドキュメントでは、日本語訳にはカーソルについての記述がない。
英語ドキュメントの「Query Cursors」を参照。
改訂版 Google App Engine(Python)でKay-Frameworkを使い、メールを受信する
「改訂版 Google App Engine(Python)でKay-Frameworkを使い、メールを受信する « 山本隆の開発日誌」より。
以前に掲載した記事「Google App Engine(Python)でKay-Frameworkを使い、メールを受信する」をKayのメール受信用のハンドラークラスを使う方法に書き直しました。
プロジェクトの作成
サンプルのプロジェクトを作成します。
ここではアプリケーションIDを「myproject」としています。
python kay/manage.py startproject myproject
cd myproject
アプリケーションを作成します。
python manage.py startapp myapp
settings.pyを編集します。
settings.py
INSTALLED_APPS = (
'myapp',
)APP_MOUNT_POINTS = {
'myapp': '/',
}
アプリケーションを動かし、設定が正しく行われているか確認します。
開発サーバーを起動します。
python manage.py runserver
「http://localhost:8080/」にアクセスし、「Hello」と表示されることを確認します。
GAE にアップロードします。
python manage.py appcfg update
「http://アプリケーションID.appspot.com/」にアクセスして、「Hello」と表示されることを確認します。
※Kayの導入について詳しくはKay チュートリアルをご覧ください。
メールの受信設定
Kay-Frameworkでメールを受信できるように設定します。
app.yamlを編集します。
次の値を追加し、メール受信機能を有効にします。
app.yaml
inbound_services:
- mail
メール受信用ハンドラーを定義します。
myapp/views.py
import logging
from kay.handlers.mail import MailBaseHandler
class MyMailHandler(MailBaseHandler):
def receive(self, mail_message, address):
'''メール受信処理
@param mail_message メールオブジェクト(google.appengine.api.mail.InboundEmailMessage)
@param address メールを受け取ったメールアドレス
'''
logging.debug('receiving_email')
myapp/urls.pyを編集し、「/_ah/mail/」へのリクエストに対して行う処理を設定します。
myapp/urls.py
view_groups = [
ViewGroup(
Rule('/', endpoint='index', view='myapp.views.index'),
Rule('/_ah/mail/<address>', endpoint='receive_mail',
view=('myapp.views.MyMailHandler', (), {})),
)
]
以上で、メールを受信すると、myapp.views.MyMailHandler.receive()が呼び出されるようになりました。
認証機能
開発環境でメールの受信テストを行うためには、管理者権限が必要です。
そこで、Kay-Frameworkの認証機能を有効にします。
settings.py
INSTALLED_APPS = (
'kay.auth', #追加
'myapp',
)MIDDLEWARE_CLASSES = (
'kay.sessions.middleware.SessionMiddleware', #追加
'kay.auth.middleware.AuthenticationMiddleware', #追加
)
「http://localhost:8080/」にアクセスしたときに、ログインフォームを表示するようにします。
admin_requiredデコレータでindexを修飾します。
myapp/views.py
from kay.auth.decorators import admin_required@admin_required
def index(request):
return render_to_response('myapp/index.html', {'message': 'Hello'})
「http://localhost:8080/」にアクセスして、ログインフォームが表示されることを確認します。
メールの受信処理
開発環境でメールの受信処理を呼び出してみましょう。
開発サーバーを起動します。
python manage.py runserver
「http://localhost:8080/_ah/admin/inboundmail」にアクセスして、メールを送ってみます。
receiving_email関数が呼ばれ、ログに「receiving_email」と出力されます。
次のようなエラーメッセージが表示された場合、管理者権限でログインしていないことが原因です。
「http://localhost:8080/」にアクセスして、「Sign in as Administrator」をチェックしてログインしてください。
Message send failure
Current logged in user is not authorized to view this page
メールの解析
受信したメールを解析します。
メールアドレスの解析
メールアドレスを解析する関数を作成します。
myapp/views.py
from email.Utils import parseaddr, getaddresses
from email.Header import decode_headerdef _parseaddress(message, field):
'''sender,to,ccから名前とメールアドレスを取得するジェネレータ
@param message メールのメッセージオブジェクト(google.appengine.api.mail.InboundEmailMessage)
@field フィールとを表す文字列(sender,to,cc)
@return (名前,メールアドレス)のtuple
'''
if hasattr(message, field):
for (name, addr) in getaddresses([getattr(message, field)]):
if name: #名前があればデコードする
(name, charset) = decode_header(name)[0]
name = name.decode(charset)
yield (name, addr)
メールのFrom,To,Ccには複数のメールアドレスが登録されている場合があります。
この関数では、(名前,メールアドレス)のtupleをメールアドレスの数だけ返します。
このままでは使いにくいので、解析結果を文字列に変換する関数を作成します。
myapp/views.py
def _join_address(gen):
'''_parseaddress関数で解析したメールアドレスを整形します。
@param gen _parseaddress
@return 名前<メールアドレス> の形に整形した文字列
'''
return u' '.join([u'%s<%s>' % addr for addr in gen])
これでメールアドレスを取得できるようになりました。
次のようにして取得することができます。
#送信者
sender = _join_address(_parseaddress(mail_message, 'sender'))
#宛先
to = _join_address(_parseaddress(mail_message, 'to'))
#CC
cc = _join_address(_parseaddress(mail_message, 'cc'))
_parseaddress関数と_join_address関数は、一つにまとめてもいいでしょう。
メールの件名の解析
メールの件名は、そのままではエンコードされていて読めません。
件名を解析する関数を作成します。
myapp/views.py
from email.Header import decode_headerdef _parsesubject(message):
'''デコードしたメールの件名を取得する
@param message メールのメッセージオブジェクト(google.appengine.api.mail.InboundEmailMessage)
@return デコードしたメールの件名
'''
if not hasattr(message, 'subject'): return u''
(subject, charset) = decode_header(message.subject)[0]
if not charset: charset = 'utf-8'
return subject.decode(charset)
この関数を使用することで、メールの件名を取得できます。
#件名
subject = _parsesubject(mail_message)
メールの日付の解析
メールの日付はRFC 2822形式の文字列になっています。
このままでは扱いにくいですので、datetimeオブジェクトに変換する関数を作成します。
myapp/views.py
import datetime
from email.Utils import parsedatedef _parsedate(date):
'''日付を解析してdatetimeオブジェクトを返す
@param date RFC 2822形式の日付を表す文字列
@return datetimeオブジェクト
'''
return datetime.datetime(*parsedate(date)[0:6])
次のようにして、メールの日付を表すdatetimeオブジェクトを取得できます。
#日付
date = _parsedate(mail_message.date)
メールの本文を取得する
メールの最初のテキストパートを取得する関数を作成します。
myapp/views.py
def _parsebody(message):
'''メールの最初のテキストパートを取得する
'''
content_type, payload = message.bodies(content_type='text/plain').next()
return payload.decode()
次のようにしてメールの本文を取得することができます。
#本文
body = _parsebody(mail_message)
HTMLメールが送られてきたときの対応は、今回は省略します。
メールの内容をデータストアに保存する
メールの内容をデータストアに保存するためのモデルを作成します。
myapp/models.py
from google.appengine.ext import dbclass Email(db.Model):
sender = db.StringProperty()
to = db.StringProperty()
cc = db.StringProperty()
subject = db.StringProperty()
date = db.DateTimeProperty()
body = db.TextProperty()
受信したメールを解析して、データストアに保存する処理は次のようになります。
myapp/views.py
from google.appengine.api import mail
from myapp import models
from kay.handlers.mail import MailBaseHandler
class MyMailHandler(MailBaseHandler):
def receive(self, mail_message, address):
'''メール受信処理
@param mail_message メールオブジェクト(google.appengine.api.mail.InboundEmailMessage)
@param address メールを受け取ったメールアドレス
'''
#送信者
sender = _join_address(_parseaddress(mail_message, 'sender'))
#宛先
to = _join_address(_parseaddress(mail_message, 'to'))
#CC
cc = _join_address(_parseaddress(mail_message, 'cc'))
#件名
subject = _parsesubject(mail_message)
#日付
date = _parsedate(mail_message.date)
#本文
body = _parsebody(mail_message) models.Email(sender=sender,
to=to,
cc=cc,
subject=subject,
date=date,
body=body,
).put()
開発サーバーで動作確認
開発環境でメールの受信処理を呼び出してみましょう。
開発サーバーを起動します。
python manage.py runserver
「http://localhost:8080/_ah/admin/inboundmail」にアクセスして、メールを送ってみます。
メールを送信できたら、「http://localhost:8080/_ah/admin/datastore」にアクセスして、送信したメールの内容がデータストアに登録されているか確認します。
GAEで動作確認
GAE にアップロードします。
python manage.py appcfg update
それでは、メールを送信してみましょう。
メールアドレスは
適当な文字列@アプリケーションID.appspotmail.com
となります。
メールアドレスが見つからない旨のエラーメールがかえってきた場合は、メール受信機能が有効になっていません。
app.yamlの設定を確認してください。
送信したメールの内容がデータストアに登録されているか確認します。
最後に
メールを解析する関数は、google.appengine.api.mail.InboundEmailMessageのサブクラスを作り、そこに実装してもいいかもしれません。
今回は単純なテキストメールのみを扱い、HTMLメールや添付ファイル、携帯電話のメールの対応などは、扱いませんでした。
リクエストがあれば、続編を書くかもしれません。
以上で、App Engineでメールを受信する方法の説明を終わります。
不具合がありましたら、お知らせいただけると喜びます。
関連ページ
Google App Engineの定番フレームワーク Kay のバージョン1.0.0がついにリリース
「Google App Engineの定番フレームワーク Kay のバージョン1.0.0がついにリリース | 山本隆の開発日誌」より。
Google App Engineの定番フレームワーク「Kay」のバージョン1.0.0がついにリリースされました。
Kay 1.0.0の主な新機能(「kay-1.0.0 をリリースしました」より)
モデル定義から RESTful API の自動生成
(Kayドキュメント 汎用ビューグループ RESTfull API)モデル定義から CRUD+list 機能の自動生成
OpenID, OAuth, Facebook connect 用の新しい認証バックエンド
より分り易い新しいURLマッピングの文法
(Kayドキュメント URLマッピング Introducing a new interface for urlmapping)OwnerProperty をはじめとするプロパティの追加
フル機能のテストヘルパ
(Kayドキュメント Testの実施)カスタム管理スクリプトを追加できるようになりました
(Kayドキュメント 管理用スクリプト)Nuke がバンドルされました
(Nuke)
(Kayドキュメント kay.ext package kay.ext.nuke)その他小さな改善点やバグ修正
Google App Engine用フレームワークKayでTaskQueueを簡単に扱う
「Google App Engine用フレームワークKayでTaskQueueを簡単に扱う | 山本隆の開発日誌」より。
「Kay でも deferred を使おう – Kays daddy」に、Kayでdeferredを使う方法が紹介されていました。
Google App Engine用フレームワークKayでは、deferredを使うことで、TaskQueueを簡単に扱うことができます。
まず初期設定ですが、元の記事ではapp.yamlとurls.pyを編集するように書かれていました。
現在のKayでは、app.yamlもurls.pyも初期状態でdeferredの設定が行われており、追加する必要はありませんでした。
deferredを使うには、deferred.defer()で関数と引数を指定します。
myapp/views.py
from google.appengine.ext import deferred
def do_something_later(foo):
#バックグラウンドで行う処理
import logging
logging.debug(keys)
…def index(request):
#バックグラウンドで行う処理を登録する
deferred.defer(do_something_later, 'foo')
…
deferは次のように定義されています。
def defer(obj, *args, **kwargs):
objは実行可能なオブジェクト、argsとkwargsはobjの引数に使用されます。
引数の「_countdown」「_eta」「_name」「_transactional」「_url」「_queue」は、
google.appengine.api.labs.taskqueue.Taskクラスの引数になります。
(参照:The Task Class – Google App Engine – Google Code)
def index(request):
deferred.defer(do_something_later, 20, _queue="foo", _countdown=60)
Google App Engine/Python関連のメモ
- The History of Python.jp: 新スタイルクラスの内部の話
- http://python-history-jp.blogspot.com/2010/07/httppython-history.html
- Google AppsからすべてのGoogleサービスにアクセスできるようになるらしい : ライフハッカー[日本版]
- http://www.lifehacker.jp/2010/07/100705googleaccounttransition.html