Question

Say you are developing on a Django project with a few people using (for example) git. When you do git pull you might get some South migrations, however, you might not notice (for some reason). Then when you go on developing, you might run into python exceptions because you didn't do the migrations. Now sometimes it can be some time before you find out you forgot this, which is pretty annoying.

So therefor I was thinking, can't South detect that you haven't done all the migrations and just throw an exception if so?

I imagen this could be a setting which you could turn off if you want to keep developing without doing the migration.

Was it helpful?

Solution 2

Ok I made some middleware which does what I want. When you do a request it checks which migrations you haven't applied yet and raises an exception. Be sure to use this middleware only in development!

You can also find the source on https://gist.github.com/gitaarik/5974176

from south import migration
from south.models import MigrationHistory


class SouthUnranMigrationCheck(object):

    def process_request(self, request):
        '''
        Checks if you ran all South migrations. If not, it will throw an
        exception (DidNotApplyAllMigrations).
        '''

        unapplied_migrations = self.unapplied_migrations()

        if len(unapplied_migrations) > 0:

            message = u'You haven\'t run the following migrations: {}'.format(
                u''.join(
                    [u'\n  "{}" in app "{}".'.format(name, app)
                    for name, app in unapplied_migrations]
                )
            )

            raise DidNotApplyAllMigrations(message)

    def unapplied_migrations(self):
        '''
        Returns a list of tuples of unapplied migrations. The tuples consist of
        a migration name and an app label.
        '''

        applied_migrations = self.applied_migrations()
        unapplied_migrations = []

        for app_migration_files in migration.all_migrations():

            for migration_file in app_migration_files:

                app_label = migration_file.app_label()
                migration_name = migration_file.name()

                if migration_name not in applied_migrations[app_label]:
                    unapplied_migrations.append((migration_name, app_label))

        return unapplied_migrations

    def applied_migrations(self):
        '''
        Returns a dictionary with the app name in the key, and a list of
        migrations in the value.
        '''

        applied_migrations = {}

        for applied_migration in MigrationHistory.objects.all():

            if applied_migration.app_name not in applied_migrations:
                applied_migrations[applied_migration.app_name] = []

            applied_migrations[applied_migration.app_name].append(
                applied_migration.migration)

        return applied_migrations


class DidNotApplyAllMigrations(Exception):
    '''
    Exception that indicates that you havent run all migrations.
    '''
    pass

OTHER TIPS

ok, that's my way.

I have a app south_test with 3 migrations, that's the ´python manage.py migrate --list´ shows:

south_test
  (*) 0001_initial
  (*) 0002_auto__add_person
  ( ) 0003_auto__add_field_person_age

That is (not too) magic code:

from south.models import MigrationHistory
from south.migration import Migrations

all_migrations = Migrations('south_test')
applied_migrations = MigrationHistory.objects.filter(app_name='south_test')

not_applied = list(set(all_migrations) - set([migration.get_migration() for migration in applied_migrations]))

Now you have not_applied migrations. Maybe there are some details with ghost migrations.

See the migrate command of south for details.

Hope this helps!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top