Google App Engine for Python 的参考文献列表
在谷歌应用引擎中,有一种叫做ListProperty的东西,它可以用来存放一系列的项目(就像数组一样)。你还可以指定这些项目的类型,比如字符串、整数等等。
谷歌应用引擎还允许你使用ReferenceProperty。ReferenceProperty“包含”对另一个谷歌应用引擎模型实体的引用。当你访问这个ReferenceProperty时,它会自动获取它所指向的实际实体。这非常方便,因为你不需要先获取一个键,然后再去获取那个键对应的实体。
不过,我没有看到有类似ListReferenceProperty(或者ReferenceListProperty)的东西。我想要的是一个可以存放对其他实体的引用列表,并且在我尝试访问列表中的元素时,这些引用会自动被解析。现在我能做到的最接近的方式是存放一系列的db.Key对象。我可以用这些键手动从服务器上获取它们对应的实体。
有没有什么好的解决方案呢?基本上,我希望能有一个可以自动解析引用到其他实体的集合。我几乎可以通过存放其他实体的键来实现,但我希望它能“知道”这些是键项,并且能够为我提供解析的服务。
谢谢
2 个回答
你说得对,确实没有内置的 ReferenceListProperty
。你可以自己写一个,定制的属性子类通常比较简单,但要做到完美其实比你想象的要难,特别是在处理引用和缓存引用列表的时候。
不过,你可以使用 db.ListProperty(db.Key)
,它允许你存储一个键的列表。这样,你可以选择单独加载每个键,或者一次性批量加载所有键,使用 db.get()
操作。虽然这需要你自己处理解析的步骤,但它也让你在何时解析实体上有更多的控制权。
第一步:
使用 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)