Commit e46e15e5 authored by Andrew Godwin's avatar Andrew Godwin
Browse files

Fixed #22204: Bad circular-dep-breaking if more than one per run

parent 8ce3ea68
Loading
Loading
Loading
Loading
+12 −2
Original line number Diff line number Diff line
@@ -94,9 +94,14 @@ class MigrationAutodetector(object):
        # Phase 2 is progressively adding pending models, splitting up into two
        # migrations if required.
        pending_new_fks = []
        added_phase_2 = set()
        while pending_add:
            # Is there one we can add that has all dependencies satisfied?
            satisfied = [(m, rf) for m, rf in pending_add.items() if all((al, mn) not in pending_add for f, al, mn in rf)]
            satisfied = [
                (m, rf)
                for m, rf in pending_add.items()
                if all((al, mn) not in pending_add for f, al, mn in rf)
            ]
            if satisfied:
                (app_label, model_name), related_fields = sorted(satisfied)[0]
                model_state = self.to_state.models[app_label, model_name]
@@ -107,7 +112,10 @@ class MigrationAutodetector(object):
                        fields=model_state.fields,
                        options=model_state.options,
                        bases=model_state.bases,
                    )
                    ),
                    # If it's already been added in phase 2 put it in a new
                    # migration for safety.
                    new=any((al, mn) in added_phase_2 for f, al, mn in related_fields),
                )
                for field_name, other_app_label, other_model_name in related_fields:
                    # If it depends on a swappable something, add a dynamic depend'cy
@@ -117,6 +125,7 @@ class MigrationAutodetector(object):
                    elif app_label != other_app_label:
                            self.add_dependency(app_label, other_app_label)
                del pending_add[app_label, model_name]
                added_phase_2.add((app_label, model_name))
            # Ah well, we'll need to split one. Pick deterministically.
            else:
                (app_label, model_name), related_fields = sorted(pending_add.items())[0]
@@ -342,6 +351,7 @@ class MigrationAutodetector(object):
                else:
                    new_name = "%04i_%s" % (next_number, self.suggest_name(migration.operations))
                name_map[(app_label, migration.name)] = (app_label, new_name)
                next_number += 1
                migration.name = new_name
        # Now fix dependencies
        for app_label, migrations in changes.items():
+3 −2
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ class AutodetectorTests(TestCase):
    author_proxy_notproxy = ModelState("testapp", "AuthorProxy", [], {}, ("testapp.author", ))
    publisher = ModelState("testapp", "Publisher", [("id", models.AutoField(primary_key=True)), ("name", models.CharField(max_length=100))])
    publisher_with_author = ModelState("testapp", "Publisher", [("id", models.AutoField(primary_key=True)), ("author", models.ForeignKey("testapp.Author")), ("name", models.CharField(max_length=100))])
    publisher_with_book = ModelState("testapp", "Publisher", [("id", models.AutoField(primary_key=True)), ("author", models.ForeignKey("otherapp.Book")), ("name", models.CharField(max_length=100))])
    other_pony = ModelState("otherapp", "Pony", [("id", models.AutoField(primary_key=True))])
    other_stable = ModelState("otherapp", "Stable", [("id", models.AutoField(primary_key=True))])
    third_thing = ModelState("thirdapp", "Thing", [("id", models.AutoField(primary_key=True))])
@@ -243,7 +244,7 @@ class AutodetectorTests(TestCase):
        """
        # Make state
        before = self.make_project_state([])
        after = self.make_project_state([self.author_with_book, self.book])
        after = self.make_project_state([self.author_with_book, self.book, self.publisher_with_book])
        autodetector = MigrationAutodetector(before, after)
        changes = autodetector._detect_changes()
        # Right number of migrations?
@@ -251,7 +252,7 @@ class AutodetectorTests(TestCase):
        self.assertEqual(len(changes['otherapp']), 2)
        # Right number of actions?
        migration1 = changes['testapp'][0]
        self.assertEqual(len(migration1.operations), 1)
        self.assertEqual(len(migration1.operations), 2)
        migration2 = changes['otherapp'][0]
        self.assertEqual(len(migration2.operations), 1)
        migration3 = changes['otherapp'][1]