mirror of
https://github.com/django/django.git
synced 2025-03-12 02:12:38 +00:00
Fixed #34333 -- Fixed migration operations ordering when adding index/constraint on new foreign key.
Thanks Simon Charette and David Wobrock for reviews.
This commit is contained in:
parent
dde2537fbb
commit
4b1bfea284
@ -1304,6 +1304,7 @@ class MigrationAutodetector:
|
|||||||
|
|
||||||
def generate_added_indexes(self):
|
def generate_added_indexes(self):
|
||||||
for (app_label, model_name), alt_indexes in self.altered_indexes.items():
|
for (app_label, model_name), alt_indexes in self.altered_indexes.items():
|
||||||
|
dependencies = self._get_dependencies_for_model(app_label, model_name)
|
||||||
for index in alt_indexes["added_indexes"]:
|
for index in alt_indexes["added_indexes"]:
|
||||||
self.add_operation(
|
self.add_operation(
|
||||||
app_label,
|
app_label,
|
||||||
@ -1311,6 +1312,7 @@ class MigrationAutodetector:
|
|||||||
model_name=model_name,
|
model_name=model_name,
|
||||||
index=index,
|
index=index,
|
||||||
),
|
),
|
||||||
|
dependencies=dependencies,
|
||||||
)
|
)
|
||||||
|
|
||||||
def generate_removed_indexes(self):
|
def generate_removed_indexes(self):
|
||||||
@ -1367,6 +1369,7 @@ class MigrationAutodetector:
|
|||||||
app_label,
|
app_label,
|
||||||
model_name,
|
model_name,
|
||||||
), alt_constraints in self.altered_constraints.items():
|
), alt_constraints in self.altered_constraints.items():
|
||||||
|
dependencies = self._get_dependencies_for_model(app_label, model_name)
|
||||||
for constraint in alt_constraints["added_constraints"]:
|
for constraint in alt_constraints["added_constraints"]:
|
||||||
self.add_operation(
|
self.add_operation(
|
||||||
app_label,
|
app_label,
|
||||||
@ -1374,6 +1377,7 @@ class MigrationAutodetector:
|
|||||||
model_name=model_name,
|
model_name=model_name,
|
||||||
constraint=constraint,
|
constraint=constraint,
|
||||||
),
|
),
|
||||||
|
dependencies=dependencies,
|
||||||
)
|
)
|
||||||
|
|
||||||
def generate_removed_constraints(self):
|
def generate_removed_constraints(self):
|
||||||
@ -1425,6 +1429,22 @@ class MigrationAutodetector:
|
|||||||
dependencies.append((through_app_label, through_object_name, None, True))
|
dependencies.append((through_app_label, through_object_name, None, True))
|
||||||
return dependencies
|
return dependencies
|
||||||
|
|
||||||
|
def _get_dependencies_for_model(self, app_label, model_name):
|
||||||
|
"""Return foreign key dependencies of the given model."""
|
||||||
|
dependencies = []
|
||||||
|
model_state = self.to_state.models[app_label, model_name]
|
||||||
|
for field in model_state.fields.values():
|
||||||
|
if field.is_relation:
|
||||||
|
dependencies.extend(
|
||||||
|
self._get_dependencies_for_foreign_key(
|
||||||
|
app_label,
|
||||||
|
model_name,
|
||||||
|
field,
|
||||||
|
self.to_state,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return dependencies
|
||||||
|
|
||||||
def _get_altered_foo_together_operations(self, option_name):
|
def _get_altered_foo_together_operations(self, option_name):
|
||||||
for app_label, model_name in sorted(self.kept_model_keys):
|
for app_label, model_name in sorted(self.kept_model_keys):
|
||||||
old_model_name = self.renamed_models.get(
|
old_model_name = self.renamed_models.get(
|
||||||
|
@ -2720,6 +2720,65 @@ class AutodetectorTests(BaseAutodetectorTests):
|
|||||||
changes, "testapp", 0, 0, model_name="author", constraint=added_constraint
|
changes, "testapp", 0, 0, model_name="author", constraint=added_constraint
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_add_constraints_with_new_model(self):
|
||||||
|
book_with_unique_title_and_pony = ModelState(
|
||||||
|
"otherapp",
|
||||||
|
"Book",
|
||||||
|
[
|
||||||
|
("id", models.AutoField(primary_key=True)),
|
||||||
|
("title", models.CharField(max_length=200)),
|
||||||
|
("pony", models.ForeignKey("otherapp.Pony", models.CASCADE)),
|
||||||
|
],
|
||||||
|
{
|
||||||
|
"constraints": [
|
||||||
|
models.UniqueConstraint(
|
||||||
|
fields=["title", "pony"],
|
||||||
|
name="unique_title_pony",
|
||||||
|
)
|
||||||
|
]
|
||||||
|
},
|
||||||
|
)
|
||||||
|
changes = self.get_changes(
|
||||||
|
[self.book_with_no_author],
|
||||||
|
[book_with_unique_title_and_pony, self.other_pony],
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertNumberMigrations(changes, "otherapp", 1)
|
||||||
|
self.assertOperationTypes(
|
||||||
|
changes,
|
||||||
|
"otherapp",
|
||||||
|
0,
|
||||||
|
["CreateModel", "AddField", "AddConstraint"],
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_add_index_with_new_model(self):
|
||||||
|
book_with_index_title_and_pony = ModelState(
|
||||||
|
"otherapp",
|
||||||
|
"Book",
|
||||||
|
[
|
||||||
|
("id", models.AutoField(primary_key=True)),
|
||||||
|
("title", models.CharField(max_length=200)),
|
||||||
|
("pony", models.ForeignKey("otherapp.Pony", models.CASCADE)),
|
||||||
|
],
|
||||||
|
{
|
||||||
|
"indexes": [
|
||||||
|
models.Index(fields=["title", "pony"], name="index_title_pony"),
|
||||||
|
]
|
||||||
|
},
|
||||||
|
)
|
||||||
|
changes = self.get_changes(
|
||||||
|
[self.book_with_no_author],
|
||||||
|
[book_with_index_title_and_pony, self.other_pony],
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertNumberMigrations(changes, "otherapp", 1)
|
||||||
|
self.assertOperationTypes(
|
||||||
|
changes,
|
||||||
|
"otherapp",
|
||||||
|
0,
|
||||||
|
["CreateModel", "AddField", "AddIndex"],
|
||||||
|
)
|
||||||
|
|
||||||
def test_remove_constraints(self):
|
def test_remove_constraints(self):
|
||||||
"""Test change detection of removed constraints."""
|
"""Test change detection of removed constraints."""
|
||||||
changes = self.get_changes(
|
changes = self.get_changes(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user