That's what I'm doing.
I have a MigratingModel class that inherits all my models. Here is migrating_model.py:
"""Models which know how to migrate themselves""" import logging from google.appengine.ext import db from google.appengine.api import memcache class MigrationError(Exception): """Error migrating""" class MigratingModel(db.Model): """A model which knows how to migrate itself. Subclasses must define a class-level migration_version integer attribute. """ current_migration_version = db.IntegerProperty(required=True, default=0) def __init__(self, *args, **kw): if not kw.get('_from_entity'):
MigratingModel intercepts the conversion from the raw data store object to the full db.Model instance. If current_migration_version behind the class of the last migration_version , then it runs a series of migrate_N() methods that do a heavy lift.
For example:
"""Migrating model example""" # ...imports... class User(MigratingModel): migration_version = 3 name = db.StringProperty() # deprecated: use first_name and last_name first_name = db.StringProperty() last_name = db.StringProperty() age = db.IntegerProperty() invalid = db.BooleanProperty() # to search for bad users def migrate_1(self): """Convert the unified name to dedicated first/last properties.""" self.first_name, self.last_name = self.name.split() def migrate_2(self): """Ensure the users' names are capitalized.""" self.first_name = self.first_name.capitalize() self.last_name = self.last_name.capitalize() def migrate_3(self): """Detect invalid accounts""" if self.age < 0 or self.age > 85: self.invalid = True
On a busy site, the migrate () method should retry if db.put() fails, and possibly db.put() critical error if the migration does not work.
I have not received this yet, but at some point I will probably mix my migrations from a separate file.
Final thoughts
Hard to test App Engine. It is difficult to access your production data in a test environment, and it is currently difficult to make a coherent snapshot backup. Therefore, for major changes, consider creating a new version that uses a completely different model name that imports from the old model and migrates as needed. (For example, User2 instead of User ). Thus, if you need to revert to a previous version, you have an effective data backup.
Jason smith
source share