Last active
August 29, 2015 14:00
-
-
Save erichiggins/11407998 to your computer and use it in GitHub Desktop.
GAE NDB Revisions: Create automatic versions of your datastore models, allowing you to undo changes!
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# -*- coding: utf-8 -*- | |
""" | |
Create automatic versions of your App Engine Datastore Models, allowing you to undo changes! | |
Usage: | |
import gae_ndb_revisions | |
# Add two properties to your Model(s). | |
class MyModel(ndb.Model): | |
... | |
ndb_rev_number = ndb.IntegerProperty(default=0) # First rev will be 1, see pre-put. | |
ndb_rev_latest = ndb.KeyProperty(kind=gae_ndb_revisions.Revision) | |
ndb_rev_previous = ndb.KeyProperty(kind=gae_ndb_revisions.Revision) | |
# Add the method calls to your Model hooks. | |
def _pre_put_hook(self): | |
# Tasks to run before saving. | |
gae_ndb_revisions.incr_revision(self) | |
def _post_put_hook(self, future): | |
# Tasks to run after saving. | |
gae_ndb_revisions.save_revision(self, future) | |
""" | |
__author__ = 'Eric Higgins' | |
__copyright__ = 'Copyright 2013, Eric Higgins' | |
__version__ = '0.0.2' | |
__email__ = '[email protected]' | |
__status__ = 'Development' | |
import logging | |
from google.appengine.ext import ndb | |
__all__ = [ | |
'incr_revision', | |
'save_revision', | |
'Revision', | |
] | |
def incr_revision(obj): | |
"""Increment the version number. Intended to be called by pre_put_hook.""" | |
obj.ndb_rev_number += 1 # Increment revision number. | |
obj.ndb_rev_previous = obj.ndb_rev_latest | |
_, new_id = Revision.allocate_ids(1) | |
obj.ndb_rev_latest = ndb.Key(Revision, new_id) | |
logging.debug(u'%s revision is now %d with ID %d', obj.key, obj.ndb_rev_number, new_id) | |
def save_revision(obj, future): | |
"""Save a new Revision. Intended to be called by post_put_hook.""" | |
logging.debug('Asserting a successful put.') | |
future.get_result() | |
logging.debug(u'Making call to save revision of %s', obj.key) | |
Revision.save(obj) | |
class Revision(ndb.Expando): | |
"""Stored copy of a revisioned Model, stored copy of latest version.""" | |
obj_key = ndb.KeyProperty() | |
obj_dict = ndb.PickleProperty() | |
revision = ndb.IntegerProperty() | |
previous_key = ndb.KeyProperty(kind=Revision) | |
created = ndb.DateTimeProperty(auto_now_add=True) | |
modified = ndb.DateTimeProperty(auto_now=True) | |
@classmethod | |
def save(cls, obj): | |
"""Save a copy of the object instance dictionary as a new Revision.""" | |
logging.info(u'Saving revision %d of %s', obj.ndb_rev_number, obj.key) | |
obj_dict = obj.to_dict() | |
rev = cls(key=obj.ndb_rev_latest, obj_key=obj_key, revision=obj.ndb_rev_number, previous=obj.ndb_rev_previous, obj_dict=obj_dict) | |
# TODO(eric): Use put_async. | |
return rev.put() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Also the Kind might be useful.