Fixed #22861: Internal migrations done first so __first__ works
Thanks to Chris Beaven.
This commit is contained in:
parent
09b63a7cce
commit
2cee1d4642
|
@ -74,7 +74,7 @@ class MigrationGraph(object):
|
|||
for node in self.nodes:
|
||||
if not any(key[0] == node[0] for key in self.dependencies.get(node, set())) and (not app or app == node[0]):
|
||||
roots.add(node)
|
||||
return roots
|
||||
return sorted(roots)
|
||||
|
||||
def leaf_nodes(self, app=None):
|
||||
"""
|
||||
|
@ -88,7 +88,7 @@ class MigrationGraph(object):
|
|||
for node in self.nodes:
|
||||
if not any(key[0] == node[0] for key in self.dependents.get(node, set())) and (not app or app == node[0]):
|
||||
leaves.add(node)
|
||||
return leaves
|
||||
return sorted(leaves)
|
||||
|
||||
def dfs(self, start, get_children):
|
||||
"""
|
||||
|
|
|
@ -223,8 +223,19 @@ class MigrationLoader(object):
|
|||
self.graph = MigrationGraph()
|
||||
for key, migration in normal.items():
|
||||
self.graph.add_node(key, migration)
|
||||
# Add all internal dependencies first to ensure __first__ dependencies
|
||||
# find the correct root node.
|
||||
for key, migration in normal.items():
|
||||
for parent in migration.dependencies:
|
||||
if parent[0] != key[0] or parent[1] == '__first__':
|
||||
# Ignore __first__ references to the same app (#22325)
|
||||
continue
|
||||
self.graph.add_dependency(key, parent)
|
||||
for key, migration in normal.items():
|
||||
for parent in migration.dependencies:
|
||||
if parent[0] == key[0]:
|
||||
# Internal dependencies already added.
|
||||
continue
|
||||
parent = self.check_key(parent, key[0])
|
||||
if parent is not None:
|
||||
self.graph.add_dependency(key, parent)
|
||||
|
|
|
@ -51,11 +51,11 @@ class GraphTests(TestCase):
|
|||
# Test roots and leaves
|
||||
self.assertEqual(
|
||||
graph.root_nodes(),
|
||||
set([('app_a', '0001'), ('app_b', '0001')]),
|
||||
[('app_a', '0001'), ('app_b', '0001')],
|
||||
)
|
||||
self.assertEqual(
|
||||
graph.leaf_nodes(),
|
||||
set([('app_a', '0004'), ('app_b', '0002')]),
|
||||
[('app_a', '0004'), ('app_b', '0002')],
|
||||
)
|
||||
|
||||
def test_complex_graph(self):
|
||||
|
@ -105,11 +105,11 @@ class GraphTests(TestCase):
|
|||
# Test roots and leaves
|
||||
self.assertEqual(
|
||||
graph.root_nodes(),
|
||||
set([('app_a', '0001'), ('app_b', '0001'), ('app_c', '0001')]),
|
||||
[('app_a', '0001'), ('app_b', '0001'), ('app_c', '0001')],
|
||||
)
|
||||
self.assertEqual(
|
||||
graph.leaf_nodes(),
|
||||
set([('app_a', '0004'), ('app_b', '0002'), ('app_c', '0002')]),
|
||||
[('app_a', '0004'), ('app_b', '0002'), ('app_c', '0002')],
|
||||
)
|
||||
|
||||
def test_circular_graph(self):
|
||||
|
|
|
@ -142,6 +142,26 @@ class LoaderTests(TestCase):
|
|||
],
|
||||
)
|
||||
|
||||
@override_settings(MIGRATION_MODULES={
|
||||
"migrations": "migrations.test_migrations_first",
|
||||
"migrations2": "migrations2.test_migrations_2_first",
|
||||
})
|
||||
@modify_settings(INSTALLED_APPS={'append': 'migrations2'})
|
||||
def test_first(self):
|
||||
"""
|
||||
Makes sure the '__first__' migrations build correctly.
|
||||
"""
|
||||
migration_loader = MigrationLoader(connection)
|
||||
self.assertEqual(
|
||||
migration_loader.graph.forwards_plan(("migrations", "second")),
|
||||
[
|
||||
("migrations", "thefirst"),
|
||||
("migrations2", "0001_initial"),
|
||||
("migrations2", "0002_second"),
|
||||
("migrations", "second"),
|
||||
],
|
||||
)
|
||||
|
||||
@override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations"})
|
||||
def test_name_match(self):
|
||||
"Tests prefix name matching"
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("migrations", "thefirst"),
|
||||
("migrations2", "0002_second"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
|
||||
migrations.DeleteModel("Tribble"),
|
||||
|
||||
migrations.RemoveField("Author", "silly_field"),
|
||||
|
||||
migrations.AddField("Author", "rating", models.IntegerField(default=0)),
|
||||
|
||||
migrations.CreateModel(
|
||||
"Book",
|
||||
[
|
||||
("id", models.AutoField(primary_key=True)),
|
||||
("author", models.ForeignKey("migrations.Author", null=True)),
|
||||
],
|
||||
)
|
||||
|
||||
]
|
|
@ -0,0 +1,30 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
operations = [
|
||||
|
||||
migrations.CreateModel(
|
||||
"Author",
|
||||
[
|
||||
("id", models.AutoField(primary_key=True)),
|
||||
("name", models.CharField(max_length=255)),
|
||||
("slug", models.SlugField(null=True)),
|
||||
("age", models.IntegerField(default=0)),
|
||||
("silly_field", models.BooleanField(default=False)),
|
||||
],
|
||||
),
|
||||
|
||||
migrations.CreateModel(
|
||||
"Tribble",
|
||||
[
|
||||
("id", models.AutoField(primary_key=True)),
|
||||
("fluffy", models.BooleanField(default=True)),
|
||||
],
|
||||
)
|
||||
|
||||
]
|
|
@ -0,0 +1,26 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("migrations", "__first__"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
|
||||
migrations.CreateModel(
|
||||
"OtherAuthor",
|
||||
[
|
||||
("id", models.AutoField(primary_key=True)),
|
||||
("name", models.CharField(max_length=255)),
|
||||
("slug", models.SlugField(null=True)),
|
||||
("age", models.IntegerField(default=0)),
|
||||
("silly_field", models.BooleanField(default=False)),
|
||||
],
|
||||
),
|
||||
|
||||
]
|
|
@ -0,0 +1,22 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [("migrations2", "0001_initial")]
|
||||
|
||||
operations = [
|
||||
|
||||
migrations.CreateModel(
|
||||
"Bookstore",
|
||||
[
|
||||
("id", models.AutoField(primary_key=True)),
|
||||
("name", models.CharField(max_length=255)),
|
||||
("slug", models.SlugField(null=True)),
|
||||
],
|
||||
),
|
||||
|
||||
]
|
Loading…
Reference in New Issue