我在ComputedProperty
中有一个StructuredProperty
,在首次创建对象时不会更新。
当我创建对象address_components_ascii
时,不会保存。该字段在数据存储查看器中根本不可见。但是,如果我get()
然后立即再次put()
(即使没有更改任何内容),ComputedProperty
也会按预期工作。 address_components
字段正常运行。
我尝试清除数据库,并删除整个数据库文件夹,但没有成功。
我在Windows 7上使用本地开发服务器。我还没有在GAE上测试它。
以下是代码:
class Item(ndb.Model):
location = ndb.StructuredProperty(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']
答案 0 :(得分:1)
我刚刚在dev服务器上尝试了这个代码并且它的工作正常。可以在放置之前和之后访问计算属性。
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']
答案 1 :(得分:1)
真正的问题似乎是GAE在_prepare_for_put()
上调用StructuredProperty
相对于周围_pre_put_hook()
的{{1}}调用的顺序。
我写信给Model
中的address_components
。我假设GAE在Item._pre_put_hook()
上调用ComputedProperty
之前计算了StructuredProperty
的{{1}}。从ComputedProperty读取会导致重新计算其值。
我将此添加到_pre_put_hook()
:
Item
我将返回值保存到虚拟变量以避免IDE警告。
答案 2 :(得分:0)
这似乎是ndb
的限制。只需执行put()
后跟get()
和另一个put()
即可。它速度较慢,但仅在第一次创建对象时才需要。
我添加了这个方法:
def double_put(self):
return self.put().get().put()
是put()
的替代品。
当我put()
新对象时,我呼叫MyObject.double_put()
而不是MyObject.put()
。