简体   繁体   中英

Django South: detecting if fake migrations were applied in production

I'm adding South to an existing application which has many installations however I don't have access to production environments due to security reasons.
We can only supply Python installation script that will be run by persons that often don't have any knowledge about Django, South, etc.

I'm aware of the fact that for existing installations any future upgrade will have to start with executing:

manage.py syncdb
manage.py migrate --all 0001 --fake

and any new installations will start with:

manage.py syncdb
manage.py migrate -all


Is there any way to detect if south initial migrations were already applied (eg by detecting if south_migfationhistory table exists) in a database agnostic way (perhaps with Django itself) ?
What I would like to do is:

(pseudocode)
db = database.connect(dbname, user, password)
if db.table_existst('south_migrationhistory'):
  execute 'manage.py syncdb'
  execute 'manage.py migrate --all'
else:
  execute 'manage.py syncdb'
  execute 'manage.py migrate --all 0001 --fake'
  execute 'manage.py migrate --all'

For future reference this is how I ended up doing this:

if args.settings_dir not in sys.path:
  sys.path.append(args.settings_dir)

os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'

#try to query db for existing objects, e.g. user groups
#in order to detect if we are upgrading an existing installation
from django.db.utils import DatabaseError
try:
  from django.contrib.auth.models import Group
  tmp = len(Group.objects.all()) #evaluate to force db query
  updating = True
except DatabaseError as e:
  updating = False

#try to query db for South migrations in order to detect if South was already applied
#in this installation (if not then accessing MigrationHistory will throw an excepion)
try:
  from south.models import MigrationHistory
  has_south = bool(len(MigrationHistory.objects.all()))
except ImportError as e:
  print 'ERROR: Error importing South migration history: ' + str(e)
  print 'Exiting'
  exit(1)
except DatabaseError as e:
  has_south = False

#syncdb to create south_migrationhistory table, portal models will not be synced
from django.core.management import execute_from_command_line
argv = ['manage.py', 'syncdb', '--settings=settings', '--pythonpath=' + args.settings_dir]
execute_from_command_line(argv)

#if we are updating existing installation and South wasn't already applied
#then initial migration has to be 'faked' in order to sync with existing tables
if updating and not has_south:
  print 'INFO: Faking initial database migration...'
  argv = ['manage.py', 'migrate', '--all', '0001', '--fake',
          '--settings=settings', '--pythonpath=' + args.settings_dir]
  execute_from_command_line(argv)

#run normal migrations
print 'INFO: Applying database migrations...'
argv = ['manage.py', 'migrate', '--all',
        '--settings=settings', '--pythonpath=' + args.settings_dir]
execute_from_command_line(argv)

A solution to your situation is actually an outstanding ticket for South:

http://south.aeracode.org/ticket/430

The ticket suggests creating a flag --autofake-first , which will determine whether any initial tables exist, and if they do, will fake the first migration but run the rest as normal. This is perfect if you've just converted an app to South, but you need this change as part of a remote or continuous deployment strategy.

It's been open for 3 years, and while it's been implemented for a while, it is waiting on being merged. Feel free to comment on the issue if you'd like this functionality ;-)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM