15

ReferenceProperty 在处理两个模块之间的引用时非常有帮助。狐狸示例:

class UserProf(db.Model):
    name = db.StringProperty(required=True)

class Team(db.Model):
    manager_name = db.ReferenceProperty(UserProf, collection_name='teams')
    name = db.StringProperty(required=True)
  • 要使用团队实例获取“manager_name”,我们使用 team_ins.manager_name。
  • 为了获得由特定用户实例管理的“团队”,我们使用 user_instance.teams 并迭代。

它看起来不是很容易理解吗?

在使用 NDB 做同样的事情时,我们必须修改

db.ReferenceProperty(UserProf, collection_name='teams')-->ndb.KeyProperty(kind=UserProf)

  • team_ins.manager_name.get()会给你经理的名字
  • 要获得由特定用户管理的所有团队,我们必须这样做

    for team in Team.query(Team.manager_name == user_ins.key): 
        print "team  name:", team.name
    

正如你所看到的,在 db 中处理这些场景看起来比在 ndb 中更容易和可读。

  • ndb 中移除 ReferenceProperty 的原因是什么?
  • 甚至 db 的查询 user_instance.teams 也会做与 ndb 的 for 循环中相同的事情。但是在 ndb 中,我们明确提到了使用 for 循环。
  • 当我们执行 user_instance.teams 时,幕后发生了什么?

提前致谢..

4

2 回答 2

26

蒂姆解释得很好。我们发现一个常见的反模式是使用引用属性并一次加载它们,因为符号“entity.property1.property2”并没有清楚地表明第一个点会导致数据库“获取”操作。因此,我们通过强制您编写“entity.property1.get().property2”使其更加明显,并且我们通过简单地说“entity.property1.get_async”使批量预取变得更容易(没有尼克博客中的复杂解决方案) ()” 用于一堆实体 - 这会将单个批处理获取操作排队而不阻塞结果,并且当您下次使用“entity.property1.get().property2”引用这些属性中的任何一个时,这不会启动另一个获取操作,但只是等待该批次完成(第二次执行此操作时,完全的)。此外,这种方式的进程内和内存缓存集成是免费的。

于 2013-05-29T19:12:40.573 回答
7

我不知道为什么 Guido 没有实现引用属性的答案。

但是我发现使用 pre_fetch_refprops http://blog.notdot.net/2010/01/ReferenceProperty-prefetching-in-App-Engine花了很多时间 (通过使用 get_value_for_datastore 抓取所有键来预获取所有参考属性, ) 然后它对键执行 get_multi 。

这大大提高了效率。

此外,如果引用的对象不存在,则在尝试获取对象时会出错。

如果你腌制一个有引用的对象,你最终腌制的次数可能比你计划的要多得多。

所以我发现除了一种情况,你有一个实体并且你想用 .name 类型的访问器来获取引用的对象,你必须跳过各种各样的箍来防止被引用的实体被获取。

于 2013-05-29T07:08:58.523 回答