2008年6月6日金曜日

展覧会案内webサービスを作る(2)

"Google AppEngineを使って展覧会案内葉書のデータベースサービスを作ります"

チュートリアルで簡易掲示板みたいなのを動かしてみて、なんとなくわかったこと

  • python はvbやc#のようなbegin..endや{ } の代わりに、インデントで文を区切る
  • データベースに登録するクラスは class XXX(db.Model) で定義する
以上で、とにかく、データベースを作ってみることにする

データストアクラスを作る

まず展覧会案内葉書に必要な項目について考える
  1. データ作成者
  2. データ作成日(更新日)
  3. 葉書の画像URL、裏表あるので、複数のリンクを保存する必要がある
  4. 展覧会タイトル
  5. 展覧会開始日、終了日
  6. 開場時間
  7. 会場
  8. 会場住所
  9. 地図
  10. イベント(オープニングパーティがあるよ!とか、最終日は4時までとかの情報
とりあえずこんなぐらいで、PostCardクラスを作ってみる
クラスのメンバは
db.UserProperty
db.StringProperty
db.DateTimeProperty
等の型が使える

Types and Property Classesに一覧がある。
DateTimePropertyには作成時に現在の日付を初期値として自動的に割り当てることができる。でも日本との時差で9時間ずれている

LinkPropertyとかEmailPropertyなんてものもあるけど、よくわからないのでStringPropertyにして、葉書画像のリンクの様に複数データが必要なものはStringListPropertyとした

class PostCard(db.Model):
author = db.UserProperty()
images = db.StringListProperty()
title = db.StringProperty()
members = db.StringListProperty()
update = db.DateTimeProperty(auto_now=True)
date_s = db.DateProperty()
date_e = db.DateProperty()
opentime = db.TimeProperty()
closetime = db.TimeProperty()
place = db.StringProperty()
address = db.PostalAddressProperty()
zip = db.StringProperty()
phone = db.PhoneNumberProperty()
point = db.GeoPtProperty()
content = db.StringProperty(multiline=True)
comment = db.StringProperty(multiline=True)
closed = db.StringListProperty()
events = db.StringListProperty()
visible = db.BooleanProperty()
メインページの表示を作る

メインページはurl:http://forlune.appspot.com/にアクセスしたときに表示するhtmlを生成する
チュートリアルを改造して MainPage クラスを作る
GETリクエストを受け取ったときの処理を記述
class MainPage(webapp.RequestHandler):
def get(self):
.....
GET リクエストで受け取るクエリとして
kind=all,yyyy-mm-dd
start=n
maxcount=n
span=day,week,month
とする。kind=allでPostCardを全て表示する、日付を指定するとその日以降開催している展覧会の葉書を表示する様にする
spanで表示期間を1日,1週間,1ヶ月とする
start,maxcountで表示する枚数を制限する

プログラムでクエリはPOST,GETリクエストともに
self.request.get('kind')
の様に受け取る
文字列を数値に変換するために int() 関数を使う、変換に失敗したら例外が発生するので、例外処理も含めておく
try:
start=int(self.request.get('start'))
except:
start=0
PostCardをデータベースから取り出す
entitys=PostCard.all().order('-update')
これで全部のPostCardを更新順に取り出せる

指定した日付で終了していないPostCardを取り出す
データベースから条件を指定してデータを取り出すには、gqlとかいうのを使うらしい
Getting Entities Using a Query
gqlはsqlに似たデータベース言語だけど、sqlすら使ったこと無いので良くわからん
よくわからないけど、日付で範囲を指定してデータを取り出すには以下の様に記述すると出来た
entitys = PostCard.gql("WHERE date_e >= :1 "+"ORDER BY date_e  LIMIT 10",startdate)
ここでstartdate は表示する期間の開始日をセットしてある、同じように終了日をenddateに設定してる。つまり4/1から一週間の間に開催中の展覧会を表示したい場合はstartdateに4/1、enddateに4/7をセットする

本当は、指定した期間内に開催中のPostCardを抽出するようにしたいのだけど、gqlでは抽出条件に異なるプロパティに対して不等号を条件として設定することが出来ないみたい?
例えば date_s <=enddate AND date_e >= startdate こういう条件はダメ?

仕方が無いのでenddate側の絞込みはプログラムでやってみる
entitys = [entity for entity in entitys if entity.date_s <= enddate]
これはリストの内包表記というやつで、
new_entitys = []
for entity in entitys:
if entity.date_s <= enddate:
new_entiys.append(entity)
entitys = new_entitys
を簡単に書ける
これをやっちゃうとentitysもうQueryクラスではなくてリストになる?

Queryクラスってのが、いまひとつ理解できてないけど、リストとは違うみたい
ここには

QueryオブジェクトもGqlQueryオブジェクトも、実はアプリがその結果にアクセスしようとするまではクエリを実行しないんだ。つまり、アプリが結果にアクセスしようとした時にクエリが実行され、Modelクラスのインスタンスとしてメモリに読み込まれるってコトだな。ちなみに、どっちのクラスも結果へのアクセス方法は2つある。1つがfetch()メソッドを使う方法、そしてもう1つがイテレータインターフェースだ。

fetch()メソッドは返却される結果の上限値を「fetch(上限値)」の形式で表現するぜ!それからオプションでスキップするオフセットを指定する事もできる。書き方としてはfetch(上限値, offset=オフセット値)って感じになる。上限値の部分で指定してるのが、datastoreから引っ張ってくる結果の数で、オフセットで指定するのが実際にメソッドの結果として返される結果の数ってコトになってるゼ! 簡単にまとめると、まずはメモリ上に上限値までの全ての結果を引っ張ってきて、それから初めてオフセットに従った結果を返す為の処理が行われるってワケだな。つまり、オフセットで指定する値はdatastoreからとってくる結果の数には影響を与えなくて、あくまでもfetch()メソッドの実行結果を返す段階で使われるダケって話だ。

って書いてあった。クエリの結果にアクセスするにはfetch()、かイテレータインターフェイスとある。上記の場合はイテレータインターフェイスということになるのかな

つづく

0 件のコメント: