[1.7.x] Fixed #23092: Squashing handles external dependencies

This commit is contained in:
Andrew Godwin 2014-07-29 10:22:00 -07:00
parent cc875e94cf
commit 8e7fdfdb6f
2 changed files with 28 additions and 3 deletions

View File

@ -3,11 +3,13 @@ from optparse import make_option
from django.core.management.base import BaseCommand, CommandError from django.core.management.base import BaseCommand, CommandError
from django.utils import six from django.utils import six
from django.conf import settings
from django.db import connections, DEFAULT_DB_ALIAS, migrations from django.db import connections, DEFAULT_DB_ALIAS, migrations
from django.db.migrations.loader import AmbiguityError from django.db.migrations.loader import AmbiguityError
from django.db.migrations.executor import MigrationExecutor from django.db.migrations.executor import MigrationExecutor
from django.db.migrations.writer import MigrationWriter from django.db.migrations.writer import MigrationWriter
from django.db.migrations.optimizer import MigrationOptimizer from django.db.migrations.optimizer import MigrationOptimizer
from django.db.migrations.migration import SwappableTuple
class Command(BaseCommand): class Command(BaseCommand):
@ -67,12 +69,23 @@ class Command(BaseCommand):
if answer != "y": if answer != "y":
return return
# Load the operations from all those migrations and concat together # Load the operations from all those migrations and concat together,
# along with collecting external dependencies and detecting
# double-squashing
operations = [] operations = []
dependencies = set()
for smigration in migrations_to_squash: for smigration in migrations_to_squash:
if smigration.replaces: if smigration.replaces:
raise CommandError("You cannot squash squashed migrations! Please transition it to a normal migration first: https://docs.djangoproject.com/en/1.7/topics/migrations/#squashing-migrations") raise CommandError("You cannot squash squashed migrations! Please transition it to a normal migration first: https://docs.djangoproject.com/en/1.7/topics/migrations/#squashing-migrations")
operations.extend(smigration.operations) operations.extend(smigration.operations)
for dependency in smigration.dependencies:
if isinstance(dependency, SwappableTuple):
if settings.AUTH_USER_MODEL == dependency.setting:
dependencies.add(("__setting__", "AUTH_USER_MODEL"))
else:
dependencies.add(dependency)
elif dependency[0] != smigration.app_label:
dependencies.add(dependency)
if self.verbosity > 0: if self.verbosity > 0:
self.stdout.write(self.style.MIGRATE_HEADING("Optimizing...")) self.stdout.write(self.style.MIGRATE_HEADING("Optimizing..."))
@ -97,7 +110,7 @@ class Command(BaseCommand):
# Make a new migration with those operations # Make a new migration with those operations
subclass = type("Migration", (migrations.Migration, ), { subclass = type("Migration", (migrations.Migration, ), {
"dependencies": [], "dependencies": dependencies,
"operations": new_operations, "operations": new_operations,
"replaces": replaces, "replaces": replaces,
}) })

View File

@ -146,8 +146,20 @@ class Migration(object):
return project_state return project_state
class SwappableTuple(tuple):
"""
Subclass of tuple so Django can tell this was originally a swappable
dependency when it reads the migration file.
"""
def __new__(cls, value, setting):
self = tuple.__new__(cls, value)
self.setting = setting
return self
def swappable_dependency(value): def swappable_dependency(value):
""" """
Turns a setting value into a dependency. Turns a setting value into a dependency.
""" """
return (value.split(".", 1)[0], "__first__") return SwappableTuple((value.split(".", 1)[0], "__first__"), value)