# management.py: from django.dispatch import dispatcher from django.db.models import signals, get_apps, get_models from django.db import backend, connection, transaction from sphene.community.models import ApplicationChangelog from datetime import datetime def do_changelog(app, created_models, verbosity, **kwargs): app_models = get_models( app ) if app_models == None: return sql = () for clazz in app_models: changelog = getattr(clazz, 'changelog', None) if not changelog: continue #changelog = get_changelog(None) version = None currentversion = changelog[-1][0] currentcl = ApplicationChangelog( app_label = clazz._meta.app_label, model = clazz._meta.object_name.lower(), version = currentversion, applied = datetime.today(), ) try: appcl = ApplicationChangelog.objects.filter( app_label = clazz._meta.app_label, model = clazz._meta.object_name.lower(), ).latest() version = appcl.version if currentversion == version: continue except ApplicationChangelog.DoesNotExist: # See if model was just created... if clazz in created_models: # Store latest version in changelog ... currentcl.save() continue # No need to do anything ... else: # We need to do the whole changelog ... version = None for change in changelog: date, changetype, stmt = change if version != None and version >= date: # This change was already applied ... continue if changetype == 'alter': sqlstmt = 'ALTER TABLE %s %s' % (backend.quote_name(clazz._meta.db_table), stmt) sql += (sqlstmt,) print "%s: SQL Statement: %s" % (date, sqlstmt) elif changetype == 'update': sqlstmt = 'UPDATE %s %s' % (backend.quote_name(clazz._meta.db_table), stmt) sql += (sqlstmt,) print "%s: SQL Statement: %s" % (date, sqlstmt) else: print "Unknown changetype: %s - %s" % (changetype, str(change)) # Store new version ... currentcl.save() if len(sql) > 0: confirm = 'x' while confirm not in ('yes', 'no'): confirm = raw_input("Detected changes - Do you want to execute SQL Statements ? (yes,no): ") if confirm == 'yes': curs = connection.cursor() for sqlstmt in sql: curs.execute( sqlstmt ) transaction.commit_unless_managed() else: print "Not updating database. You have to do this by hand !" dispatcher.connect(do_changelog, signal=signals.post_syncdb) # models.py class ApplicationChangelog(models.Model): app_label = models.CharField(maxlength = 250) model = models.CharField(maxlength = 250) version = models.CharField(maxlength = 250) applied = models.DateTimeField() class Meta: get_latest_by = 'applied' # Example changelog entries: class Post(models.Model): # your model fields & co come here # .... # the changelog entry define the schema evolution over time # The list arguments are: # 1. A unique and incrementing ID of the changelog entry # 2. The type of statement ('alter' and 'update' supported) # 3. The SQL statement from AFTER the table name. the 'ALTER TABLE xxxx' or 'UPDATE xxxx' is autogenerated. # i usually use ' ' to identify each changelog entry # but since it uses simple string comparsion anything which simply counts whould be # sufficient. changelog = ( ( '2007-04-07 00', 'alter', 'ALTER author_id DROP NOT NULL', ), ( '2007-06-16 00', 'alter', 'ADD markup varchar(250) NULL', ), )