PolyModel @ Timeline

先日のGoogle App EngineのSDK1.1.8のリリースで、PolyModelが使えるようになったので、さっそくGAWareで使うことにした。今までは、TimelineとImageはBaseModelで作っていた。そして、書きソース(Pastebinで見る)のように、一度Imageを積み込み、そのkey().id()をTimelineのIntegerPropertyに突っ込んでた。そして取得するときは、image = Image.get_by_id(timeline.photo)という風に取得していた。

from appengine_django import models
from google.appengine.ext import db

class Timeline(models.BaseModel):
    """
    Usage::
        user = users.get_current_user()
        message = 'test'
        timeline = Timeline(author = user, message = message)
        timeline.save()
    """
    author = db.UserProperty()
    message = db.StringProperty(_('message'), required=True)
    photo = db.IntegerProperty()

class Image(models.BaseModel):
    author = db.UserProperty(required=True)
    # image
    data = db.BlobProperty(required=True)
    format = db.StringProperty(required=True)

from google.appengine.api import users, images
from django.core.files.uploadedfile import SimpleUploadedFile as UploadedFile

file = request.FILES['image']
format = file.content_type
data = images.Image(file.read())._image_data
author = users.get_current_user()
image = Image(author = author, data = data, format = format)
image.put()
timeline = Timeline(author = author, message = 'test', photo = image.key().id())
timeline.put()

今後、どこかのサービスのように画像以外に、リンクや、Youtubeのビデオ、ファイルなどをアップできるようにする時は、Timelineを改造しないといけない(※実際は定数で、Timelineが何を含んでいるのかを持っていた)。でっ待望のPolyModelに書き換えた。

from appengine_django import models
from google.appengine.ext import db
from google.appengine.ext.db import polymodel

class Timeline(polymodel.PolyModel):
    """
    Usage::
        user = users.get_current_user()
        message = 'test'
        timeline = Timeline(author = user, message = message)
        timeline.save()
    """
    author = db.UserProperty()
    message = db.StringProperty(_('message'), required=True)
    photo = db.IntegerProperty()

class ImageTimeline(Timeline):
    # image
    data = db.BlobProperty(required=True)
    format = db.StringProperty(required=True)

    @classmethod
    def class_name(cls):
        return 'Photo'

from google.appengine.api import users, images
from django.core.files.uploadedfile import SimpleUploadedFile as UploadedFile

file = request.FILES['image']
format = file.content_type
data = images.Image(file.read())._image_data
author = users.get_current_user()
image = ImageTimeline(author = author, message = 'test', data = data, format = format)
image.put()

# get photos
imagetimelines = Timeline.all().filter('class =', 'Photo')

PolyModelを使うと、あるモデルを派生してかけるので、Timelineに持たせたいアイテムが増えたら増えた分だけモデルを書いていけばいい。影響範囲は案外少ない(diffはここ)。拡張したくなりそうなモデルはすべてPolyModelで。

Bitbucketへ移行

GAWare, django-on-gaeをbitbucketへ移行しました。動作が軽快だし、あと気軽にforkしていただけるのが魅力的(笑)。git使ってた時に、*.pycまでコミットしちゃってたので、今回は.hgignoreを書いて、色々とコミットするファイルを制限した。
# use glob syntax.
syntax: glob
*.pyc
*.pyo
*~
.*.swp
*.kpf

# switch to regexp syntax.
syntax:regexp
/\.
DS_Store
まず、globで拡張子がpyc, pyo, swp, kpfなファイルをコミットしないようにした。swpはvimのスワップファイル。kpfはkomodo edit用のプロジェクトファイル。テンプレート書くときとかはkomodo使っちゃうんだよね。あとregexpでMercurialが使うファイルと、マックの隠しファイルDS_Storeをコミットしないようにした。マカーじゃないんだけどね。

DjangoのModelで複数のフィルターを利用する場合のTips

id:Voluntasが、早速コードレビューしてくださった。6つぐらいるけど、今日はとりあえず、Modelのリファクタリングのアドバイスを実装した。diffはここ
timeline = Timeline.all()
timeline = timeline.filter('author =', user)
timeline = timeline.filter('group =', group)
と今まで書いていたけど、Pythonは長いコードを'\'を使って改行できる。それを利用し、Modelで複数のfilterを利用する場合でも以下のように書く。
timeline = Timeline.all() \
  .filter('author =', user) \
  .filter('group =', group)
他にも色々とアドバイスを頂いているので、コードを見やすくしていくことにする。 Special thanks voluntas.

GAE SDK 1.1.8 リリース

Google App EngineのSDK 1.1.8がリリースされました。id:Voluntas, Ianがブログで解説してますね。
  • PolyModelがサポートされました。
  • UserPropertyに auto_current_user / auto_current_user_addが追加
  • Image API に width/heightが追加
  • あとはバグフィックスとか
PolyModelのドキュメントより、以下のような使い方ができます。
from google.appengine.ext import db
from google.appengine.ext.db import polymodel

class Contact(polymodel.PolyModel):
  phone_number = db.PhoneNumberProperty()
  address = db.PostalAddressProperty()

class Person(Contact):
  first_name = db.StringProperty()
  last_name = db.StringProperty()
  mobile_number = db.PhoneNumberProperty()

class Company(Contact):
  name = db.StringProperty()
  fax_number = db.PhoneNumberProperty()

p = Person(phone_number='1-206-555-9234',
           address='123 First Ave., Seattle, WA, 98101',
           first_name='Alfred',
           last_name='Smith',
           mobile_number='1-206-555-0117')
p.put()

c = Company(phone_number='1-503-555-9123',
            address='P.O. Box 98765, Salem, OR, 97301',
            name='Data Solutions, LLC',
            fax_number='1-503-555-6622')
c.put()

for contact in Contact.all():
  # Returns both p and c.
  # ...

for person in Person.all():
  # Returns only p.
  # ...

Ianのブログにも書いてありますけど、from google.appengine.api import croninfoができていますね。cron.yamlができるんでしょうか。期待してます。cronは待ちわびてたサービス。有料だけだったりして・・・。

GAWare 公開

AppSpotで公開しているGAWareのソースコードをGPLライセンスで公開し始めました。コメントを入れたやつから公開していきます。コードが長いし、読みにくいですがご容赦ください(汗)。まだスラグ用の正規表現フィールド等はデバッグしてません…。コードレポは迷ったんですが、Google Codeを使っています。そのうち、bitbucketあたりに移行するかもしれません。バグとか、コーディングのアドバイス等色々突っ込んでいただけると喜びます。

(睡眠薬以外で)安眠できる方法

眠れない、寝つきが悪い、眠りが浅い、寝てても途中で起きてしまう等などの睡眠障害。改善しようとネットで検索して、色々と試してみることにした。まず、行動パターンから。
  • 眠れないことに対して自分を責めない、眠れないことを心配しない
  • 悩み、不安について考えない(寝る前にTODO等で課題を整理しておく)
  • 寝るときは時計は見ない、見える場所に置かない(余計ストレスになるらしい)
  • 体を温める(湯たんぽ、軽い運動、セックス)
  • 緊張をとる(深呼吸、真っ暗にする)
  • 寝る前(3時間以内)に薬、酒、煙草、カフェインは飲まない
  • 寝る前(3時間以内)に仕事をしない、ディスプレイを見ない、部屋を暗くする
  • 寝る前(8時間以内)に仮眠しない
  • 毎日30分は太陽の光を浴びる
  • 週末も平日と同じ睡眠リズムで過ごす
  • ベッド、布団は清潔に、毎日日干し(日光の香りは良い)
次に快眠に役立ちそうなガジェット達。
  • リラックス効果があるガンマアミノ酪酸(グッスミン:ライオンGABAチョコレート:グリコ、玄米)
  • 体が温まるホットミルク、ハーブティー(カモミールティーなど)
  • リラックス効果がある香り(ラベンダー等のアロマ、スプレー、芳香剤)
  • クラシック音楽
  • 自分に合った枕
参考にしたソースは以下のページ。他にもいろいろあるな。

目標管理

昨年度末に立てた目標の進捗はというと。 正月は色々と入り用ですね。6日のTopCoderには参加する予定です。その前に1回練習問題を解いとかないとですね。ということで、来週の目標です。
  • Microblogにロギングを実装
  • 5日「Google ジュース」をリーディング、TopCoder練習問題
  • 6日TopCoderに参加
  • 「ウェブ時代5つの定理 - 梅田望夫」を読む
  • TPTPテストをマスターする

GAWare (like twitter) 公開

知識が不足しすぎているので、公開までだいぶ時間がかかったけど、Twitter ライク なアプリを公開した。Django on Google App Engineで動作しています。まだ、荒削りだし、未実装の機能があるけど、メインの機能は動作している。ちなみに、http://ware.appspot.com/で公開している。
主な機能は以下。
  • ユーザ登録、プロフィール設定、アバター設定、メール通知(未実装)設定
  • グループ作成、グループ設定、アバター設定、メンバー管理
  • タイムラインの登録、お気に入り登録(未実装)、写真登録、タギング
  • プライベートメッセージ
  • ユーザ、グループそれぞれプロテクト機能
  • アプリ自体の公開、非公開(Google Appsユーザ用)設定
  • 投稿ファイル制限(マイムタイプ)
などなど。後々はGoogle Appsユーザ用にオープンにしたいけど、今のソースはとてもじゃないけど公開できない(笑)。そもそも公開されてもコメントもロギングもしてないし、可読性が低すぎるので、「えっ?」って感じだと思う。今後の目標は、
  • ローカライズ
  • ロギング
  • ソースの整備
  • 未実装機能の実装
です。あと、いろんなサービスを登録できるようなのも勉強中。 Web APIとか、OpenSocialとか、FriendConnectとか。亀のようなスピードですが・・・。