星期五, 10月 08, 2010

Entity group

慢慢對App enginedata model有感覺了, 之前還習慣用SQL的時候, 總覺得要抓什麼都得用query, 所以在App engine裡也不自覺地動不動就用下面這三種方法來抓data, 即使只要抓一筆資料回來.



q = FooModel.all()
q.filter()
q.get()

for item in q:
    xxxx

results = q.fetch(100)
for item in results:
    yyyy

後來發現其實很多資料本身就有唯一性的特質, 像是user的id或是email, 整個table裡理論上不會有兩筆重覆的資料. 那在存這個entity的時候, 就可以直接用這個欄位指定這個entity的key_name.

class User(db.Model):
    name = db.StringProperty()
    email = db.StringProperty()

class TestHandler(webapp.RequestHandler):
    def get(self):
        name = self.request.get('name')
        user = User(key_name = name, name = name)
        user.put()

這樣如果要驗這個user在不在的話, 就只要判斷User.get(name)是不是None, 不用另外做query. 要改的話也可以直接改完就put().

如果不指定key_name的話, 這個entity就只有id, 沒有name. 如果指定name的話, id就會是None. 兩個應該是互斥的, 所以Key class才有一個叫id_or_name()的method.

用了一陣子之後, 又看到了可以設entity group, 每個entity可以指定一個parent, 如果不指定, 自已就是entity root. 如果互為parent<->child關係的entities, 可以放在一個transaction裡處理.

grandpa = User(key_name = 'grandpa', name = 'Abraham Simpson')
grandpa.put()
father = User(parent = grandpa, name = 'Homer Simpson')
father.put()
son = User(parent = father, name = 'Bart Simpson')
son.put()

只要在建entity的時候指定parent參數即可指定兩者間的關係, 要注意的是要在parent entity已經被put()後才能當作parent.

實際上key是長的像下面這樣的東西
agptYWMtZ3RhYmxlchALEgROb2RlIgZwYXJlbnQM
agptYWMtZ3RhYmxlciELEgROb2RlIgZwYXJlbnQMCxIETm9kZSIHY2hpbGQgMQw
agptYWMtZ3RhYmxlcjILEgROb2RlIgZwYXJlbnQMCxIETm9kZSIHY2hpbGQgMQwLEgROb2RlIgdjaGlsZCAyDA
上面的是下面一層的parent, 可以看出來每多一層就會多約20~30 bytes. 因為Key有500 bytes的限制, 經過我的實驗, 差不多可以有21層. 我是想不出來有什麼會到21層的應用... :p

如果不知道key對應的是什麼model, 可以直接用db來取得.
x = db.get(db.Key.from_path('User', 'grandpa', 'User', 'father', 'User', 'son'))
print x.name

這樣應該會印出來Bart Simpson! 找不到的話就會傳回None.

沒有留言: