避免ReferenceProperty自动解引用

标签:Google App Engine, Python

刚才在GAE论坛看到这样一个问题:
一个模型里有一个引用属性(ReferenceProperty)。获取完实体集后,想要通过该引用属性来获取指向的实体。
重点是ReferenceProperty会自动解引用,访问它时会自动查询数据库,这样就会造成多次数据库访问,而不能用gb.get()来一次获取。

举例来说就是这样:
from google.appengine.api import apiproxy_stub_map 
from google.appengine.ext import db

DB_TIME = 0

def hook(service, call, request, response):
  global DB_TIME
  DB_TIME += 1
  print DB_TIME

apiproxy_stub_map.apiproxy.GetPreCallHooks().Append('db_hook', hook, 'datastore_v3')


class M(db.Model):
  ref = db.SelfReferenceProperty()

a = M()
print 'put a'
a.put()

b = M(ref=a)
print 'put b'
b.put()

c = M(ref=b)
print 'put c'
c.put()

d = M(ref=c)
print 'put d'
d.put()

print 'start of fetching'
entites = M.all().filter('ref != ', None).fetch(3)
print 'end of fetching'

refs = [entity.ref for entity in entites]

print 'get fetching'
db.get(refs)
结果:
put a
1
put b
2
put c
3
put d
4
start of fetching
5
end of fetching
6
7
8
get fetching
Traceback (most recent call last):
#太多了,省略
BadArgumentError: Expected one of (<type 'basestring'>, <class
'google.appengine.api.datastore.Entity'>, <class
'google.appengine.api.datastore_types.Key'>); received <__main__.M
object at 0x020869D0> (a M).
其中,第6~8次访问都是entity.ref造成的。

实际上属性类有个get_value_for_datastore方法可以处理这个问题,只要把获取ref的那句改成这样即可:
refs = [M.ref.get_value_for_datastore(entity) for entity in entites]
结果:
put a
1
put b
2
put c
3
put d
4
start of fetching
5
6
end of fetching
get fetching
7
多余的数据库访问不见了,程序也不抛异常了。

最后,aetycoon里提供了一个KeyProperty,它不会自动解引用。

8条评论 你不来一发么↓ 顺序排列 倒序排列

    向下滚动可载入更多评论,或者点这里禁止自动加载

    想说点什么呢?