ComputedProperty仅在第二次put()时更新

时间:2015-05-15 18:17:22

标签: python google-app-engine google-cloud-datastore app-engine-ndb google-app-engine-python

我在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']

3 个答案:

答案 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()