Google App Engine for Python 的参考文献列表

18 投票
2 回答
2714 浏览
提问于 2025-04-16 10:09

在谷歌应用引擎中,有一种叫做ListProperty的东西,它可以用来存放一系列的项目(就像数组一样)。你还可以指定这些项目的类型,比如字符串、整数等等。

谷歌应用引擎还允许你使用ReferenceProperty。ReferenceProperty“包含”对另一个谷歌应用引擎模型实体的引用。当你访问这个ReferenceProperty时,它会自动获取它所指向的实际实体。这非常方便,因为你不需要先获取一个键,然后再去获取那个键对应的实体。

不过,我没有看到有类似ListReferenceProperty(或者ReferenceListProperty)的东西。我想要的是一个可以存放对其他实体的引用列表,并且在我尝试访问列表中的元素时,这些引用会自动被解析。现在我能做到的最接近的方式是存放一系列的db.Key对象。我可以用这些键手动从服务器上获取它们对应的实体。

有没有什么好的解决方案呢?基本上,我希望能有一个可以自动解析引用到其他实体的集合。我几乎可以通过存放其他实体的键来实现,但我希望它能“知道”这些是键项,并且能够为我提供解析的服务。

谢谢

2 个回答

6

你说得对,确实没有内置的 ReferenceListProperty。你可以自己写一个,定制的属性子类通常比较简单,但要做到完美其实比你想象的要难,特别是在处理引用和缓存引用列表的时候。

不过,你可以使用 db.ListProperty(db.Key),它允许你存储一个键的列表。这样,你可以选择单独加载每个键,或者一次性批量加载所有键,使用 db.get() 操作。虽然这需要你自己处理解析的步骤,但它也让你在何时解析实体上有更多的控制权。

13

第一步:

使用 db.ListProperty(db.Key) 来建立关系。你希望将 ListProp 放在那个在多对多关系中引用较少的实体上。这样做还会给你一个反向引用。所以:

class Spam
  prop1 = db.String
  eggs = db.List

class Eggs
  prop1 = db.string
  @property
  def spams(self):
    return Spam.all().filter('eggs', self.key())

这样就可以实现双向引用。

第二步:

创建一个工具方法,用来解除属性的引用。

def prefetch_refprops(entities, *props):
    """Dereference Reference Properties to reduce Gets.  See:
    http://blog.notdot.net/2010/01/ReferenceProperty-prefetching-in-App-Engine
    """
    fields = [(entity, prop) for entity in entities for prop in props]
    ref_keys = [prop.get_value_for_datastore(x) for x, prop in fields]
    ref_entities = dict((x.key(), x) for x in db.get(set(ref_keys)))
    for (entity, prop), ref_key in zip(fields, ref_keys):
        prop.__set__(entity, ref_entities[ref_key])
    return entities  

使用方法如下:

derefrenced_spams = prefetch_refprops(Spams, models.Spam.eggs)    

撰写回答