When working with Datastore, it is often desirable to share Model instances among functionally distinct parts of your application, in order to avoid redundant calls to db.get() and db.put().
One problem that regularly crops up when sharing like this, and often even when writing simple pieces of code, is how to track which instances have been modified, and require saving.
A simple example of this problem is when processing a form POST to update a user's profile. In order to avoid a redundant put(), your code would need to compare each of the user's provided values with the existing value stored in their profile model instance, for example:
profile = Profile.get_by_key_name('someuser')
dirty = False
for field in ['username', 'password', 'description']:
new_value = self.request.get(field)
if new_value != getattr(profile, field):
dirty = True
setattr(profile, field, new_value)
new_age = int(self.request.get('age'), 10)
dirty = dirty or (new_age != profile.age)
profile.age = new_age
if dirty:
db.put(profile)
It's clear that a very simple function is obfuscated by boilerplate code used to track whether the instance has changed.
The attached file implements a Model subclass named TrackedModel, that will automatically instrument your model classes with a magical 'dirty' variable. If any property changes value during the life of the instance, this variable will be set to true. With this class, we can now write:
profile = Profile.get_by_key_name('someuser')
for field in ['username', 'password', 'description']:
setattr(profile, field, getattr(profile, field))
profile.age = int(self.request.get('age'), 10)
if profile.dirty:
db.put(profile)
Additionally, the class overrides put() to allow replacing the last 2 lines with:
profile.put(if_dirty=True)
There, much simpler!