Andrew Godwin avatar Andrew Godwin committed 41fc76e

Allow customisable migration modules

Comments (0)

Files changed (2)

south/exceptions.py

                 '%(traceback)s' % self.__dict__)
 
 
+class InvalidMigrationModule(BrokenMigration):
+    def __str__(self):
+        return ('The migration module specified for %(app)s, %(module)r, does not exist.' % self.__dict__)
+
+
 class NoMigrations(SouthError):
     def __init__(self, application):
         self.application = application

south/migration/base.py

     def create_migrations_directory(self, application, verbose=True):
         "Given an application, ensures that the migrations directory is ready."
         app_module = app_label_to_app_module(application_to_app_label(application))
-        migrations_dir = os.path.join(
-            os.path.dirname(app_module.__file__),
-            "migrations",
-        )
+        migrations_dir = self.migrations_dir()
         # Make the directory if it's not already there
         if not os.path.isdir(migrations_dir):
             if verbose:
             open(init_path, "w").close()
     
     def migrations_dir(self):
-        "Returns the full path of the migrations directory"
-        return os.path.dirname(self._migrations.__file__)
+        """
+        Returns the full path of the migrations directory.
+        If it doesn't exist yet, returns where it would exist, based on the
+        app's migrations module (defaults to app.migrations)
+        """
+        module_path = self.migrations_module()
+        try:
+            module = __import__(module_path, {}, {}, [''])
+        except ImportError:
+            # There's no migrations module made yet; guess!
+            try:
+                parent = __import__(".".join(module_path.split(".")[:-1]), {}, {}, [''])
+            except ImportError:
+                # The parent doesn't even exist, that's an issue.
+                raise exceptions.InvalidMigrationModule(
+                    app = self.application.__name__,
+                    module = module_path,
+                )
+            else:
+                # Good guess.
+                return os.path.join(os.path.dirname(parent.__file__), module_path.split(".")[-1])
+        else:
+            # Get directory directly
+            return os.path.dirname(module.__file__)
     
     def migrations_module(self):
         "Returns the module name of the migrations module for this"
+        if hasattr(settings, "SOUTH_MIGRATION_MODULES"):
+            if self.application.__name__ in settings.SOUTH_MIGRATION_MODULES:
+                # There's an override.
+                return settings.SOUTH_MIGRATION_MODULES[self.application.__name__]
         return self._application.__name__ + '.migrations'
 
     def get_application(self):
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.