ComputedProperty 仅在第二次 put() 时更新
ComputedProperty only updates on second put()
我在 StructuredProperty
中有一个 ComputedProperty
,它在首次创建对象时不会更新。
当我创建对象时 address_components_ascii
没有被保存。该字段在数据存储查看器中根本不可见。但是如果我 get()
然后立即再次 put()
(即使没有改变任何东西), ComputedProperty
会按预期工作。 address_components
字段工作正常。
我试过清除数据库,并删除整个数据库文件夹,但没有成功。
我在 windows 7 上使用本地开发服务器。我还没有在 GAE 上测试它。
代码如下:
class Item(ndb.Model):
location = ndb.StructuredProperty(Location)
内部位置class:
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
中的一个限制。简单地做一个 put()
然后一个 get()
和另一个 put()
工作。它比较慢,但只有在第一次创建对象时才需要。
我添加了这个方法:
def double_put(self):
return self.put().get().put()
这是 put()
的直接替代品。
当我 put()
一个新对象时,我调用 MyObject.double_put()
而不是 MyObject.put()
。
我刚刚在开发服务器上尝试了这段代码,它成功了。 Computed 属性 在 put 之前和之后都可以访问。
from google.appengine.ext import ndb
class TestLocation(ndb.Model):
address = ndb.StringProperty(repeated=True)
address_ascii = ndb.ComputedProperty(lambda self: [
part.lower() for part in self.address], repeated=True)
class TestItem(ndb.Model):
location = ndb.StructuredProperty(TestLocation)
item = TestItem(id='test', location=TestLocation(
address=['Drottninggatan', 'Norrmalm']))
assert item.location.address_ascii == ['drottninggatan', 'norrmalm']
item.put()
assert TestItem.get_by_id('test').location.address_ascii == [
'drottninggatan', 'norrmalm']
真正的问题似乎是 GAE 在 StructuredProperty
上调用 _prepare_for_put()
相对于周围 Model
对 _pre_put_hook()
的调用的顺序。
我正在 Item._pre_put_hook()
中给 address_components
写信。我假设 GAE 在调用 Item
上的 _pre_put_hook()
之前计算了 StructuredProperty
的 ComputedProperty
。从 ComputedProperty 读取会导致重新计算其值。
我在 _pre_put_hook()
的末尾添加了这个:
# quick-fix: ComputedProperty not getting generated properly
# read from all ComputedProperties, to compute them again before put
_ = self.address_components_ascii
我将 return 值保存到虚拟变量以避免 IDE 警告。
我在 StructuredProperty
中有一个 ComputedProperty
,它在首次创建对象时不会更新。
当我创建对象时 address_components_ascii
没有被保存。该字段在数据存储查看器中根本不可见。但是如果我 get()
然后立即再次 put()
(即使没有改变任何东西), ComputedProperty
会按预期工作。 address_components
字段工作正常。
我试过清除数据库,并删除整个数据库文件夹,但没有成功。
我在 windows 7 上使用本地开发服务器。我还没有在 GAE 上测试它。
代码如下:
class Item(ndb.Model):
location = ndb.StructuredProperty(Location)
内部位置class:
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
中的一个限制。简单地做一个 put()
然后一个 get()
和另一个 put()
工作。它比较慢,但只有在第一次创建对象时才需要。
我添加了这个方法:
def double_put(self):
return self.put().get().put()
这是 put()
的直接替代品。
当我 put()
一个新对象时,我调用 MyObject.double_put()
而不是 MyObject.put()
。
我刚刚在开发服务器上尝试了这段代码,它成功了。 Computed 属性 在 put 之前和之后都可以访问。
from google.appengine.ext import ndb
class TestLocation(ndb.Model):
address = ndb.StringProperty(repeated=True)
address_ascii = ndb.ComputedProperty(lambda self: [
part.lower() for part in self.address], repeated=True)
class TestItem(ndb.Model):
location = ndb.StructuredProperty(TestLocation)
item = TestItem(id='test', location=TestLocation(
address=['Drottninggatan', 'Norrmalm']))
assert item.location.address_ascii == ['drottninggatan', 'norrmalm']
item.put()
assert TestItem.get_by_id('test').location.address_ascii == [
'drottninggatan', 'norrmalm']
真正的问题似乎是 GAE 在 StructuredProperty
上调用 _prepare_for_put()
相对于周围 Model
对 _pre_put_hook()
的调用的顺序。
我正在 Item._pre_put_hook()
中给 address_components
写信。我假设 GAE 在调用 Item
上的 _pre_put_hook()
之前计算了 StructuredProperty
的 ComputedProperty
。从 ComputedProperty 读取会导致重新计算其值。
我在 _pre_put_hook()
的末尾添加了这个:
# quick-fix: ComputedProperty not getting generated properly
# read from all ComputedProperties, to compute them again before put
_ = self.address_components_ascii
我将 return 值保存到虚拟变量以避免 IDE 警告。