"""Migrate management command."""importos.path,re,sysfromoptparseimportmake_optionfromdjango.core.management.baseimportBaseCommandfromdjango.confimportsettingsfromsouthimportmigrationfromsouth.migrationimportMigrationsfromsouth.exceptionsimportNoMigrationsfromsouth.dbimportDEFAULT_DB_ALIASclassCommand(BaseCommand):option_list=BaseCommand.option_list+(make_option('--all',action='store_true',dest='all_apps',default=False,help='Run the specified migration for all apps.'),make_option('--list',action='store_true',dest='show_list',default=False,help='List migrations noting those that have been applied'),make_option('--changes',action='store_true',dest='show_changes',default=False,help='List changes for migrations'),make_option('--skip',action='store_true',dest='skip',default=False,help='Will skip over out-of-order missing migrations'),make_option('--merge',action='store_true',dest='merge',default=False,help='Will run out-of-order missing migrations as they are - no rollbacks.'),make_option('--no-initial-data',action='store_true',dest='no_initial_data',default=False,help='Skips loading initial data if specified.'),make_option('--fake',action='store_true',dest='fake',default=False,help="Pretends to do the migrations, but doesn't actually execute them."),make_option('--autofake-first',action='store_true',dest='autofake_first',default=False,help="Automatically fake the first migration if it can be detected that an app already has database tables."),make_option('--db-dry-run',action='store_true',dest='db_dry_run',default=False,help="Doesn't execute the SQL generated by the db methods, and doesn't store a record that the migration(s) occurred. Useful to test migrations before applying them."),make_option('--delete-ghost-migrations',action='store_true',dest='delete_ghosts',default=False,help="Tells South to delete any 'ghost' migrations (ones in the database but not on disk)."),make_option('--ignore-ghost-migrations',action='store_true',dest='ignore_ghosts',default=False,help="Tells South to ignore any 'ghost' migrations (ones in the database but not on disk) and continue to apply new migrations."),make_option('--noinput',action='store_false',dest='interactive',default=True,help='Tells Django to NOT prompt the user for input of any kind.'),make_option('--database',action='store',dest='database',default=DEFAULT_DB_ALIAS,help='Nominates a database to synchronize. ''Defaults to the "default" database.'),)if'--verbosity'notin[opt.get_opt_string()foroptinBaseCommand.option_list]:option_list+=(make_option('--verbosity',action='store',dest='verbosity',default='1',type='choice',choices=['0','1','2'],help='Verbosity level; 0=minimal output, 1=normal output, 2=all output'),)help="Runs migrations for all apps."args="[appname] [migrationname|zero] [--all] [--list] [--skip] [--merge] [--no-initial-data] [--fake] [--db-dry-run] [--database=dbalias]"defhandle(self,app=None,target=None,skip=False,merge=False,backwards=False,fake=False,autofake_first=False,db_dry_run=False,show_list=False,show_changes=False,database=DEFAULT_DB_ALIAS,delete_ghosts=False,ignore_ghosts=False,**options):# NOTE: THIS IS DUPLICATED FROM django.core.management.commands.syncdb# This code imports any module named 'management' in INSTALLED_APPS.# The 'management' module is the preferred way of listening to post_syncdb# signals, and since we're sending those out with create_table migrations,# we need apps to behave correctly.forapp_nameinsettings.INSTALLED_APPS:try:__import__(app_name+'.management',{},{},[''])exceptImportError,exc:msg=exc.args[0]ifnotmsg.startswith('No module named')or'management'notinmsg:raise# END DJANGO DUPE CODE# if all_apps flag is set, shift app over to targetifoptions.get('all_apps',False):target=appapp=None# Migrate each appifapp:try:apps=[Migrations(app)]exceptNoMigrations:print"The app '%s' does not appear to use migrations."%appprint"./manage.py migrate "+self.argsreturnelse:apps=list(migration.all_migrations())# Do we need to show the list of migrations?ifshow_listandapps:list_migrations(apps,database,**options)ifshow_changesandapps:show_migration_changes(apps)ifnot(show_listorshow_changes):forappinapps:result=migration.migrate_app(app,target_name=target,fake=fake,autofake_first=autofake_first,db_dry_run=db_dry_run,verbosity=int(options.get('verbosity',0)),interactive=options.get('interactive',True),load_initial_data=notoptions.get('no_initial_data',False),merge=merge,skip=skip,database=database,delete_ghosts=delete_ghosts,ignore_ghosts=ignore_ghosts,)ifresultisFalse:sys.exit(1)# Migration failed, so the command fails.deflist_migrations(apps,database=DEFAULT_DB_ALIAS,**options):""" Prints a list of all available migrations, and which ones are currently applied. Accepts a list of Migrations instances. """fromsouth.modelsimportMigrationHistoryapplied_migrations=MigrationHistory.objects.filter(app_name__in=[app.app_label()forappinapps])ifdatabase!=DEFAULT_DB_ALIAS:applied_migrations=applied_migrations.using(database)applied_migration_names=['%s.%s'%(mi.app_name,mi.migration)formiinapplied_migrations]printforappinapps:print" "+app.app_label()# Get the migrations objectformigrationinapp:ifmigration.app_label()+"."+migration.name()inapplied_migration_names:applied_migration=applied_migrations.get(app_name=migration.app_label(),migration=migration.name())printformat_migration_list_item(migration.name(),applied=applied_migration.applied,**options)else:printformat_migration_list_item(migration.name(),applied=False,**options)printdefshow_migration_changes(apps):""" Prints a list of all available migrations, and which ones are currently applied. Accepts a list of Migrations instances. Much simpler, less clear, and much less robust version: grep "ing " migrations/*.py """forappinapps:printapp.app_label()# Get the migrations objectsmigrations=[migrationformigrationinapp]# we use reduce to compare models in pairs, not to generate a valuereduce(diff_migrations,migrations)defformat_migration_list_item(name,applied=True,**options):ifapplied:ifint(options.get('verbosity'))>=2:return' (*) %-80s (applied %s)'%(name,applied)else:return' (*) %s'%nameelse:return' ( ) %s'%namedefdiff_migrations(migration1,migration2):defmodel_name(models,model):returnmodels[model].get('Meta',{}).get('object_name',model)deffield_name(models,model,field):return'%s.%s'%(model_name(models,model),field)print" "+migration2.name()models1=migration1.migration_class().modelsmodels2=migration2.migration_class().models# find new modelsformodelinmodels2.keys():ifnotmodelinmodels1.keys():print' added model %s'%model_name(models2,model)# find removed modelsformodelinmodels1.keys():ifnotmodelinmodels2.keys():print' removed model %s'%model_name(models1,model)# compare modelsformodelinmodels1:ifmodelinmodels2:# find added fieldsforfieldinmodels2[model]:ifnotfieldinmodels1[model]:print' added field %s'%field_name(models2,model,field)# find removed fieldsforfieldinmodels1[model]:ifnotfieldinmodels2[model]:print' removed field %s'%field_name(models1,model,field)# compare fieldsforfieldinmodels1[model]:iffieldinmodels2[model]:name=field_name(models1,model,field)# compare field attributesfield_value1=models1[model][field]field_value2=models2[model][field]# if a field has become a class, or vice versaiftype(field_value1)!=type(field_value2):print' type of %s changed from %s to %s'%(name,field_value1,field_value2)# if classelifisinstance(field_value1,dict):# print ' %s is a class' % namepass# else regular fieldelse:type1,attr_list1,field_attrs1=models1[model][field]type2,attr_list2,field_attrs2=models2[model][field]iftype1!=type2:print' %s type changed from %s to %s'%(name,type1,type2)ifattr_list1!=[]:print' %s list %s is not []'%(name,attr_list1)ifattr_list2!=[]:print' %s list %s is not []'%(name,attr_list2)ifattr_list1!=attr_list2:print' %s list changed from %s to %s'%(name,attr_list1,attr_list2)# find added field attributesforattrinfield_attrs2:ifnotattrinfield_attrs1:print' added %s attribute %s=%s'%(name,attr,field_attrs2[attr])# find removed field attributesforattrinfield_attrs1:ifnotattrinfield_attrs2:print' removed attribute %s(%s=%s)'%(name,attr,field_attrs1[attr])# compare field attributesforattrinfield_attrs1:ifattrinfield_attrs2:value1=field_attrs1[attr]value2=field_attrs2[attr]ifvalue1!=value2:print' %s attribute %s changed from %s to %s'%(name,attr,value1,value2)returnmigration2