From 8e7fdfdb6fb0e910d5b507ba2da56a297bfba25c Mon Sep 17 00:00:00 2001
From: Andrew Godwin <andrew@aeracode.org>
Date: Tue, 29 Jul 2014 10:22:00 -0700
Subject: [PATCH] [1.7.x] Fixed #23092: Squashing handles external dependencies

---
 .../management/commands/squashmigrations.py     | 17 +++++++++++++++--
 django/db/migrations/migration.py               | 14 +++++++++++++-
 2 files changed, 28 insertions(+), 3 deletions(-)

diff --git a/django/core/management/commands/squashmigrations.py b/django/core/management/commands/squashmigrations.py
index 8795947296..ece5acb69e 100644
--- a/django/core/management/commands/squashmigrations.py
+++ b/django/core/management/commands/squashmigrations.py
@@ -3,11 +3,13 @@ from optparse import make_option
 
 from django.core.management.base import BaseCommand, CommandError
 from django.utils import six
+from django.conf import settings
 from django.db import connections, DEFAULT_DB_ALIAS, migrations
 from django.db.migrations.loader import AmbiguityError
 from django.db.migrations.executor import MigrationExecutor
 from django.db.migrations.writer import MigrationWriter
 from django.db.migrations.optimizer import MigrationOptimizer
+from django.db.migrations.migration import SwappableTuple
 
 
 class Command(BaseCommand):
@@ -67,12 +69,23 @@ class Command(BaseCommand):
                 if answer != "y":
                     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 = []
+        dependencies = set()
         for smigration in migrations_to_squash:
             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")
             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:
             self.stdout.write(self.style.MIGRATE_HEADING("Optimizing..."))
@@ -97,7 +110,7 @@ class Command(BaseCommand):
 
         # Make a new migration with those operations
         subclass = type("Migration", (migrations.Migration, ), {
-            "dependencies": [],
+            "dependencies": dependencies,
             "operations": new_operations,
             "replaces": replaces,
         })
diff --git a/django/db/migrations/migration.py b/django/db/migrations/migration.py
index 708de5393d..34878b459e 100644
--- a/django/db/migrations/migration.py
+++ b/django/db/migrations/migration.py
@@ -146,8 +146,20 @@ class Migration(object):
         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):
     """
     Turns a setting value into a dependency.
     """
-    return (value.split(".", 1)[0], "__first__")
+    return SwappableTuple((value.split(".", 1)[0], "__first__"), value)