在App Engine中访问相关对象键而不获取对象

7 投票
2 回答
604 浏览
提问于 2025-04-15 18:05

一般来说,对于一个特定的对象,做一次查询比做很多次查询要好。比如说,我有一堆“儿子”对象,每个儿子都有一个“父亲”。我先获取所有的“儿子”对象:

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 个回答

1

我更喜欢通过循环访问子对象,来获取父对象的键,使用 son.parent_key() 方法。

parent_key()

这个方法会返回当前实例的父对象的键,如果这个实例没有父对象,就返回 None。

因为所有的路径信息都保存在实例的键里理论上,我们不需要再去数据库查询父对象的键。

之后,我们可以使用 db.get() 方法一次性获取所有父对象的实例。

get(keys)

这个方法可以根据给定的一个或多个键,获取对应的实体。

参数:

keys 可以是一个键对象或者一个键对象的列表

如果提供一个键,返回的就是对应模型类的实例,如果没有找到对应的实体,则返回 None。如果提供的是一个键的列表,返回的就是一个对应的模型实例列表,如果某个键没有对应的实体,则列表中会有 None 值。

10

你可以通过查看你下载的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),这样你会开心得多;-)。

撰写回答