在App Engine中访问相关对象键而不获取对象
一般来说,对于一个特定的对象,做一次查询比做很多次查询要好。比如说,我有一堆“儿子”对象,每个儿子都有一个“父亲”。我先获取所有的“儿子”对象:
sons = Son.all()
接着,我想要获取这群儿子的所有父亲。我会这样做:
father_keys = {}
for son in sons:
father_keys.setdefault(son.father.key(), None)
然后我可以这样做:
fathers = Father.get(father_keys.keys())
现在,这里假设 son.father.key() 并不会真的去获取那个对象。我这样理解对吗?我有一堆代码是基于 object.related_object.key() 不会真的从数据库中获取 related_object 的这个前提。
我这样做是对的吗?
2 个回答
我更喜欢通过循环访问子对象,来获取父对象的键,使用 son.parent_key()
方法。
parent_key()
这个方法会返回当前实例的父对象的键,如果这个实例没有父对象,就返回 None。
因为所有的路径信息都保存在实例的键里,理论上,我们不需要再去数据库查询父对象的键。
之后,我们可以使用 db.get() 方法一次性获取所有父对象的实例。
get(keys)
这个方法可以根据给定的一个或多个键,获取对应的实体。
参数:
keys 可以是一个键对象或者一个键对象的列表。
如果提供一个键,返回的就是对应模型类的实例,如果没有找到对应的实体,则返回 None。如果提供的是一个键的列表,返回的就是一个对应的模型实例列表,如果某个键没有对应的实体,则列表中会有 None 值。
你可以通过查看你下载的App Engine SDK源代码中的appengine.ext.db来找到答案。答案是,不,没你想要的那种特殊处理:在1.3.0 SDK的源代码中,ReferenceProperty
描述符的__get__
方法(第2887行)在不知道后面会不会调用.key()
或其他任何东西之前就被调用了,所以它没有机会进行你想要的优化。
不过,看看第2929行:方法get_value_for_datastore
正好做了你想要的事情!
具体来说,不要用son.father.key()
,而是用Son.father.get_value_for_datastore(son)
,这样你会开心得多;-)。