ComputedProperty only updates on second put ()

I have one ComputedProperty

inside StructuredProperty

that doesn't update when the object is first created.

When I create an object address_components_ascii

, it is not saved. The field does not appear at all in the data store viewer. But if I get()

, then immediately put()

again (without even changing anything), it ComputedProperty

works as expected. The field is address_components

working correctly.

I have tried clearing the database and deleting the entire database folder with no success.

I am using a local dev server on Windows 7. I have not tested it on GAE.


Here's the code:

class Item(ndb.Model):
    location = ndb.StructuredProperty(Location)

      

Internal 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)

      

Normalization function

def normalize(s):
    return unicodedata.normalize('NFKD', s.decode("utf-8").lower()).encode('ASCII', 'ignore')

      


Field example address_components

:

[u'114B', u'Drottninggatan', u'Norrmalm', u'Stockholm', u'Stockholm', u'Stockholms l\xe4n', u'Sverige']

      

and address_components_ascii

, after the second put()

:

[u'114b', u'drottninggatan', u'norrmalm', u'stockholm', u'stockholm', u'stockholms lan', u'sverige']

      

+3


source to share


3 answers


The real problem was the order that GAE calls _prepare_for_put()

in StructuredProperty

with respect to the _pre_put_hook()

surrounding call Model

.

I wrote address_components

to Item._pre_put_hook()

. I assume GAE figured ComputedProperty

StructuredProperty

out before calling _pre_put_hook()

on Item

. Reading from the ComputedProperty causes its value to be recalculated.

I added this to the end _pre_put_hook()

:



# quick-fix: ComputedProperty not getting generated properly
# read from all ComputedProperties, to compute them again before put
_ = self.address_components_ascii

      

I am storing the return value for a dummy variable to avoid IDE warnings.

+1


source


I just tried this code on dev server and it worked. The computed property is available before and after 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']

      

+1


source


This appears to be a limitation in ndb

. Just executed put()

followed by get()

another put()

. This is slower, but only required when creating the object for the first time.

I added this method:

def double_put(self):
        return self.put().get().put()

      

which is a replacement for put()

.

When I am a put()

new object, I call MyObject.double_put()

instead MyObject.put()

.

0


source







All Articles