【发布时间】:2015-05-15 18:17:22
【问题描述】:
我在StructuredProperty 中有一个ComputedProperty,它在首次创建对象时不会更新。
当我创建对象时,address_components_ascii 没有被保存。该字段在数据存储查看器中根本不可见。但是,如果我 get() 然后立即再次 put()(即使没有更改任何内容),ComputedProperty 将按预期工作。 address_components 字段工作正常。
我已尝试清除数据库,并删除整个数据库文件夹,但没有成功。
我在 Windows 7 上使用本地开发服务器。我没有在 GAE 上测试过。
代码如下:
class Item(ndb.Model):
location = ndb.StructuredProperty(Location)
内部 Location 类:
class Location(ndb.Model):
address_components = ndb.StringProperty(repeated=True) # array of names of parent areas, from smallest to largest
address_components_ascii = ndb.ComputedProperty(lambda self: [normalize(part) for part in self.address_components], repeated=True)
归一化函数
def normalize(s):
return unicodedata.normalize('NFKD', s.decode("utf-8").lower()).encode('ASCII', 'ignore')
address_components 字段的示例:
[u'114B', u'Drottninggatan', u'Norrmalm', u'Stockholm', u'Stockholm', u'Stockholms l\xe4n', u'Sverige']
和address_components_ascii 字段,在第二个put() 之后:
[u'114b', u'drottninggatan', u'norrmalm', u'stockholm', u'stockholm', u'stockholms lan', u'sverige']
【问题讨论】:
-
计算属性的 ndb 文档中清楚地记录了这种行为 注意:ComputedProperties 不是在查询中计算的,而是在 put() 中计算的。如果您更新模型的架构以包含 ComputedProperty,则应记住通过加载现有实体并将其写入数据存储区来更新它们。有关更多信息,请参阅更新模型的架构
-
不,这与旧的 ndb 对象无关。这是在新对象上的 put() 上,在 put() 时模型代码中的 ComputedProperty。
-
好的,我接受。您现在遇到了事件顺序问题。正如您所发现的那样,事情并不完全正常。当与其他模型/属性一起使用时,您会发现 StructuredProperty 无法处理许多极端情况。例如 PolyModel 以及某些嵌套结构。在您的情况下,
_prepare_for_put可能会以您不期望的顺序在每个属性上被调用。_prepare_for_put在放置之前在每个属性上调用,在 ComputedProperties 的情况下,它是执行计算的触发器。 -
所以在 put() 之前手动调用 _prepare_for_put() 应该修复它,而不需要 put-get-put 序列?这看起来确实是一些极端情况下的错误,因为它看起来并不难正确实现。
-
值得一试,但这也取决于 StructuredProperty 的状态。我还注意到,声明属性的顺序没有得到遵守,因为属性存储在字典中(这意味着键的散列顺序)。您可能会发现 _prepare_for_put 是按该顺序调用的,这可能会对解决属性中复杂的依赖关系/关系产生影响。
标签: python google-app-engine google-cloud-datastore app-engine-ndb google-app-engine-python