mirror of
				https://github.com/django/django.git
				synced 2025-10-31 01:25:32 +00:00 
			
		
		
		
	Fixed #21283 -- Added support for migrations if models is a package.
Thanks Markus Holtermann for the report.
This commit is contained in:
		| @@ -41,8 +41,8 @@ class MigrationLoader(object): | ||||
|     def migrations_module(cls, app_label): | ||||
|         if app_label in settings.MIGRATION_MODULES: | ||||
|             return settings.MIGRATION_MODULES[app_label] | ||||
|         app = cache.get_app(app_label) | ||||
|         return ".".join(app.__name__.split(".")[:-1] + ["migrations"]) | ||||
|         else: | ||||
|             return '%s.migrations' % cache.get_app_package(app_label) | ||||
|  | ||||
|     def load_disk(self): | ||||
|         """ | ||||
|   | ||||
| @@ -61,20 +61,22 @@ class MigrationWriter(object): | ||||
|  | ||||
|     @property | ||||
|     def path(self): | ||||
|         migrations_module_name = MigrationLoader.migrations_module(self.migration.app_label) | ||||
|         app_module = cache.get_app(self.migration.app_label) | ||||
|         migrations_package_name = MigrationLoader.migrations_module(self.migration.app_label) | ||||
|         # See if we can import the migrations module directly | ||||
|         try: | ||||
|             migrations_module = import_module(migrations_module_name) | ||||
|             migrations_module = import_module(migrations_package_name) | ||||
|             basedir = os.path.dirname(migrations_module.__file__) | ||||
|         except ImportError: | ||||
|             app = cache.get_app(self.migration.app_label) | ||||
|             app_path = cache._get_app_path(app) | ||||
|             app_package_name = cache._get_app_package(app) | ||||
|             migrations_package_basename = migrations_package_name.split(".")[-1] | ||||
|  | ||||
|             # Alright, see if it's a direct submodule of the app | ||||
|             oneup = ".".join(migrations_module_name.split(".")[:-1]) | ||||
|             app_oneup = ".".join(app_module.__name__.split(".")[:-1]) | ||||
|             if oneup == app_oneup: | ||||
|                 basedir = os.path.join(os.path.dirname(app_module.__file__), migrations_module_name.split(".")[-1]) | ||||
|             if '%s.%s' % (app_package_name, migrations_package_basename) == migrations_package_name: | ||||
|                 basedir = os.path.join(app_path, migrations_package_basename) | ||||
|             else: | ||||
|                 raise ImportError("Cannot open migrations module %s for app %s" % (migrations_module_name, self.migration.app_label)) | ||||
|                 raise ImportError("Cannot open migrations module %s for app %s" % (migrations_package_name, self.migration.app_label)) | ||||
|         return os.path.join(basedir, self.filename) | ||||
|  | ||||
|     @classmethod | ||||
|   | ||||
| @@ -185,6 +185,12 @@ class BaseAppCache(object): | ||||
|  | ||||
|         return [elt[0] for elt in apps] | ||||
|  | ||||
|     def _get_app_package(self, app): | ||||
|         return '.'.join(app.__name__.split('.')[:-1]) | ||||
|  | ||||
|     def get_app_package(self, app_label): | ||||
|         return self._get_app_package(self.get_app(app_label)) | ||||
|  | ||||
|     def _get_app_path(self, app): | ||||
|         if hasattr(app, '__path__'):        # models/__init__.py package | ||||
|             app_path = app.__path__[0] | ||||
| @@ -380,6 +386,7 @@ cache = AppCache() | ||||
| # These methods were always module level, so are kept that way for backwards | ||||
| # compatibility. | ||||
| get_apps = cache.get_apps | ||||
| get_app_package = cache.get_app_package | ||||
| get_app_path = cache.get_app_path | ||||
| get_app_paths = cache.get_app_paths | ||||
| get_app = cache.get_app | ||||
|   | ||||
							
								
								
									
										0
									
								
								tests/migrations/migrations_test_apps/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								tests/migrations/migrations_test_apps/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -2,12 +2,15 @@ | ||||
|  | ||||
| from __future__ import unicode_literals | ||||
|  | ||||
| import copy | ||||
| import datetime | ||||
| import os | ||||
|  | ||||
| from django.utils import six | ||||
| from django.test import TestCase | ||||
| from django.db.migrations.writer import MigrationWriter | ||||
| from django.db import models, migrations | ||||
| from django.db.migrations.writer import MigrationWriter | ||||
| from django.db.models.loading import cache | ||||
| from django.test import TestCase, override_settings | ||||
| from django.utils import six | ||||
| from django.utils.translation import ugettext_lazy as _ | ||||
|  | ||||
|  | ||||
| @@ -95,3 +98,24 @@ class WriterTests(TestCase): | ||||
|         # Just make sure it runs for now, and that things look alright. | ||||
|         result = self.safe_exec(output) | ||||
|         self.assertIn("Migration", result) | ||||
|  | ||||
|     def test_migration_path(self): | ||||
|         _old_app_store = copy.deepcopy(cache.app_store) | ||||
|  | ||||
|         test_apps = [ | ||||
|             'migrations.migrations_test_apps.normal', | ||||
|             'migrations.migrations_test_apps.with_package_model', | ||||
|         ] | ||||
|  | ||||
|         base_dir = os.path.dirname(os.path.dirname(__file__)) | ||||
|  | ||||
|         try: | ||||
|             with override_settings(INSTALLED_APPS=test_apps): | ||||
|                 for app in test_apps: | ||||
|                     cache.load_app(app) | ||||
|                     migration = migrations.Migration('0001_initial', app.split('.')[-1]) | ||||
|                     expected_path = os.path.join(base_dir, *(app.split('.') + ['migrations', '0001_initial.py'])) | ||||
|                     writer = MigrationWriter(migration) | ||||
|                     self.assertEqual(writer.path, expected_path) | ||||
|         finally: | ||||
|             cache.app_store = _old_app_store | ||||
|   | ||||
		Reference in New Issue
	
	Block a user