Aaron
Aaron

Reputation: 821

Can you access the previous value of a ndb property in _pre_put_hook?

I have an ndb model as follows:

class SomeModel(ndb.Model):     
    name = ndb.StringProperty(default="")
    valid = ndb.BooleanProperty(default=False)

def some_function():
    print "fired"

When the name property is changed from what it was previously I would like the some_function() function to fire.

e.g.

$ q = SomeModel.query().get()
$ print p.name 
John
$ q.name = "Sam"
$ q.put()
"fired"

If, however the valid property is changed say from False to True I do not want some_function() to fire.

e.g.

$ q = SomeModel.query().get()
$ print p.name
Sam
$ print p.valid 
False
$ q.valid = True
$ q.put()

With using either _post_put_hook or _pre_put_hook is there a way to access the previous value of the property so I can optionally fire or not fire an external function?

Upvotes: 2

Views: 185

Answers (1)

snakecharmerb
snakecharmerb

Reputation: 55669

This approach has always seemed a bit hacky to me, but it seems to work.

You can store the attribute values on the instance in the _post_get_hook, and retrieve them in the _pre_put_hook (or the _post_put_hook):

class Foo(ndb.Model):

    ...

    @classmethod
    def _post_get_hook(cls, key, future):
        instance = future.get_result()
        if instance:
            # Store 'old' instance data as an instance attribute
            instance._before = instance.to_dict()

    def _pre_put_hook(self):
        # Check if our storage attribute exists,
        # this could be a new instance.
        if hasattr(self, '_before'):
            # Do something with 'before' data
            ...
            # clean up
            del self._before 

Edit:

Cleaning up - deleting the storage attribute may require some thought if you are going to call put on your object more than once. For standard models you could leave the attribute in place, but this could be a problem with Expando models, as the attribute will be written to the datastore.

Upvotes: 2

Related Questions