Fixed #21283 -- Added support for migrations if models is a package.

Thanks Markus Holtermann for the report.
This commit is contained in:
Loic Bistuer 2013-10-19 07:24:38 +07:00 committed by Tim Graham
parent 96d1d4e292
commit 584110417f
9 changed files with 46 additions and 13 deletions

View File

@ -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):
"""

View File

@ -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

View File

@ -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

View 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