From cb60d22bd94738174440f8d60a04c3d9c38636c9 Mon Sep 17 00:00:00 2001
From: Andrew Godwin <andrew@aeracode.org>
Date: Mon, 28 Jul 2014 10:32:43 -0700
Subject: [PATCH] Fixed #23100: Individual FK creation missing dependencies

---
 django/db/migrations/autodetector.py  | 27 ++++++++++++++++++++++++---
 tests/migrations/test_autodetector.py | 15 +++++++++++++++
 2 files changed, 39 insertions(+), 3 deletions(-)

diff --git a/django/db/migrations/autodetector.py b/django/db/migrations/autodetector.py
index 7f52b9d07c..dfbfe869fd 100644
--- a/django/db/migrations/autodetector.py
+++ b/django/db/migrations/autodetector.py
@@ -699,7 +699,7 @@ class MigrationAutodetector(object):
             old_model_name = self.renamed_models.get((app_label, model_name), model_name)
             old_model_state = self.from_state.models[app_label, old_model_name]
             new_model_state = self.to_state.models[app_label, model_name]
-            field = new_model_state.get_field_by_name(field_name)
+            field = self.new_apps.get_model(app_label, model_name)._meta.get_field_by_name(field_name)[0]
             # Scan to see if this is actually a rename!
             field_dec = self.deep_deconstruct(field)
             found_rename = False
@@ -727,6 +727,25 @@ class MigrationAutodetector(object):
                             break
             if found_rename:
                 continue
+            # Fields that are foreignkeys/m2ms depend on stuff
+            dependencies = []
+            if field.rel and field.rel.to:
+                # Account for FKs to swappable models
+                swappable_setting = getattr(field, 'swappable_setting', None)
+                if swappable_setting is not None:
+                    dep_app_label = "__setting__"
+                    dep_object_name = swappable_setting
+                else:
+                    dep_app_label = field.rel.to._meta.app_label
+                    dep_object_name = field.rel.to._meta.object_name
+                dependencies = [(dep_app_label, dep_object_name, None, True)]
+                if getattr(field.rel, "through", None) and not field.rel.through._meta.auto_created:
+                    dependencies.append((
+                        field.rel.through._meta.app_label,
+                        field.rel.through._meta.object_name,
+                        None,
+                        True
+                    ))
             # You can't just add NOT NULL fields with no default
             if not field.null and not field.has_default() and not isinstance(field, models.ManyToManyField):
                 field = field.clone()
@@ -738,7 +757,8 @@ class MigrationAutodetector(object):
                         name=field_name,
                         field=field,
                         preserve_default=False,
-                    )
+                    ),
+                    dependencies=dependencies,
                 )
             else:
                 self.add_operation(
@@ -747,7 +767,8 @@ class MigrationAutodetector(object):
                         model_name=model_name,
                         name=field_name,
                         field=field,
-                    )
+                    ),
+                    dependencies=dependencies,
                 )
 
     def generate_removed_fields(self):
diff --git a/tests/migrations/test_autodetector.py b/tests/migrations/test_autodetector.py
index 27f4af8ad9..8b13269d77 100644
--- a/tests/migrations/test_autodetector.py
+++ b/tests/migrations/test_autodetector.py
@@ -1105,3 +1105,18 @@ class AutodetectorTests(TestCase):
         self.assertOperationAttributes(changes, 'testapp', 0, 0, name="Aardvark")
         self.assertOperationAttributes(changes, 'testapp', 0, 1, name="author")
         self.assertOperationAttributes(changes, 'testapp', 0, 2, name="Author")
+
+    def test_fk_dependency_other_app(self):
+        """
+        Tests that ForeignKeys correctly depend on other apps' models (#23100)
+        """
+        # Make state
+        before = self.make_project_state([self.author_name, self.book])
+        after = self.make_project_state([self.author_with_book, self.book])
+        autodetector = MigrationAutodetector(before, after)
+        changes = autodetector._detect_changes()
+        # Right number of migrations?
+        self.assertNumberMigrations(changes, 'testapp', 1)
+        self.assertOperationTypes(changes, 'testapp', 0, ["AddField"])
+        self.assertOperationAttributes(changes, 'testapp', 0, 0, name="book")
+        self.assertEqual(changes['testapp'][0].dependencies, [("otherapp", "__first__")])