mirror of
https://github.com/django/django.git
synced 2025-06-25 05:19:13 +00:00
Fixed #35305 -- Avoided recreating constraints on fields renamed via db_column.
This commit is contained in:
parent
54402a7529
commit
b2407e4d7d
@ -1460,6 +1460,29 @@ class MigrationAutodetector:
|
||||
for attr in new_constraint.non_db_attrs:
|
||||
new_kwargs.pop(attr, None)
|
||||
|
||||
# Replace renamed fields if the db_column is preserved.
|
||||
for (
|
||||
_,
|
||||
_,
|
||||
rem_db_column,
|
||||
rem_field_name,
|
||||
_,
|
||||
_,
|
||||
field,
|
||||
field_name,
|
||||
) in self.renamed_operations:
|
||||
if field.db_column and rem_db_column == field.db_column:
|
||||
new_fields = new_kwargs["fields"]
|
||||
try:
|
||||
new_field_idx = new_fields.index(field_name)
|
||||
except ValueError:
|
||||
continue
|
||||
new_kwargs["fields"] = tuple(
|
||||
new_fields[:new_field_idx]
|
||||
+ (rem_field_name,)
|
||||
+ new_fields[new_field_idx + 1 :]
|
||||
)
|
||||
|
||||
return (old_path, old_args, old_kwargs) != (new_path, new_args, new_kwargs)
|
||||
|
||||
def create_altered_constraints(self):
|
||||
|
@ -2078,6 +2078,186 @@ class AutodetectorTests(BaseAutodetectorTests):
|
||||
new_name="renamed_foo",
|
||||
)
|
||||
|
||||
def test_rename_field_preserve_db_column_preserve_constraint(self):
|
||||
"""
|
||||
Renaming a field that already had a db_column attribute and a constraint
|
||||
generates two no-op operations: RenameField and AlterConstraint.
|
||||
"""
|
||||
before = [
|
||||
ModelState(
|
||||
"app",
|
||||
"Foo",
|
||||
[
|
||||
("id", models.AutoField(primary_key=True)),
|
||||
("field", models.IntegerField(db_column="full_field1_name")),
|
||||
("field2", models.IntegerField()),
|
||||
],
|
||||
options={
|
||||
"constraints": [
|
||||
models.UniqueConstraint(
|
||||
fields=["field", "field2"],
|
||||
name="unique_field",
|
||||
),
|
||||
],
|
||||
},
|
||||
),
|
||||
]
|
||||
after = [
|
||||
ModelState(
|
||||
"app",
|
||||
"Foo",
|
||||
[
|
||||
("id", models.AutoField(primary_key=True)),
|
||||
(
|
||||
"full_field1_name",
|
||||
models.IntegerField(db_column="full_field1_name"),
|
||||
),
|
||||
(
|
||||
"field2",
|
||||
models.IntegerField(),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"constraints": [
|
||||
models.UniqueConstraint(
|
||||
fields=["full_field1_name", "field2"],
|
||||
name="unique_field",
|
||||
),
|
||||
],
|
||||
},
|
||||
),
|
||||
]
|
||||
changes = self.get_changes(
|
||||
before, after, MigrationQuestioner({"ask_rename": True})
|
||||
)
|
||||
self.assertNumberMigrations(changes, "app", 1)
|
||||
self.assertOperationTypes(changes, "app", 0, ["RenameField", "AlterConstraint"])
|
||||
self.assertOperationAttributes(
|
||||
changes,
|
||||
"app",
|
||||
0,
|
||||
1,
|
||||
model_name="foo",
|
||||
name="unique_field",
|
||||
)
|
||||
self.assertEqual(
|
||||
changes["app"][0].operations[1].deconstruct(),
|
||||
(
|
||||
"AlterConstraint",
|
||||
[],
|
||||
{
|
||||
"constraint": after[0].options["constraints"][0],
|
||||
"model_name": "foo",
|
||||
"name": "unique_field",
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
def test_rename_field_without_db_column_recreate_constraint(self):
|
||||
"""Renaming a field without given db_column recreates a constraint."""
|
||||
before = [
|
||||
ModelState(
|
||||
"app",
|
||||
"Foo",
|
||||
[
|
||||
("id", models.AutoField(primary_key=True)),
|
||||
("field", models.IntegerField()),
|
||||
],
|
||||
options={
|
||||
"constraints": [
|
||||
models.UniqueConstraint(
|
||||
fields=["field"],
|
||||
name="unique_field",
|
||||
),
|
||||
],
|
||||
},
|
||||
),
|
||||
]
|
||||
after = [
|
||||
ModelState(
|
||||
"app",
|
||||
"Foo",
|
||||
[
|
||||
("id", models.AutoField(primary_key=True)),
|
||||
(
|
||||
"full_field1_name",
|
||||
models.IntegerField(),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"constraints": [
|
||||
models.UniqueConstraint(
|
||||
fields=["full_field1_name"],
|
||||
name="unique_field",
|
||||
),
|
||||
],
|
||||
},
|
||||
),
|
||||
]
|
||||
changes = self.get_changes(
|
||||
before, after, MigrationQuestioner({"ask_rename": True})
|
||||
)
|
||||
self.assertNumberMigrations(changes, "app", 1)
|
||||
self.assertOperationTypes(
|
||||
changes, "app", 0, ["RemoveConstraint", "RenameField", "AddConstraint"]
|
||||
)
|
||||
|
||||
def test_rename_field_preserve_db_column_recreate_constraint(self):
|
||||
"""Removing a field from the constraint triggers recreation."""
|
||||
before = [
|
||||
ModelState(
|
||||
"app",
|
||||
"Foo",
|
||||
[
|
||||
("id", models.AutoField(primary_key=True)),
|
||||
("field1", models.IntegerField(db_column="field1")),
|
||||
("field2", models.IntegerField(db_column="field2")),
|
||||
],
|
||||
options={
|
||||
"constraints": [
|
||||
models.UniqueConstraint(
|
||||
fields=["field1", "field2"],
|
||||
name="unique_fields",
|
||||
),
|
||||
],
|
||||
},
|
||||
),
|
||||
]
|
||||
after = [
|
||||
ModelState(
|
||||
"app",
|
||||
"Foo",
|
||||
[
|
||||
("id", models.AutoField(primary_key=True)),
|
||||
("renamed_field1", models.IntegerField(db_column="field1")),
|
||||
("renamed_field2", models.IntegerField(db_column="field2")),
|
||||
],
|
||||
options={
|
||||
"constraints": [
|
||||
models.UniqueConstraint(
|
||||
fields=["renamed_field1"],
|
||||
name="unique_fields",
|
||||
),
|
||||
],
|
||||
},
|
||||
),
|
||||
]
|
||||
changes = self.get_changes(
|
||||
before, after, MigrationQuestioner({"ask_rename": True})
|
||||
)
|
||||
self.assertNumberMigrations(changes, "app", 1)
|
||||
self.assertOperationTypes(
|
||||
changes,
|
||||
"app",
|
||||
0,
|
||||
[
|
||||
"RemoveConstraint",
|
||||
"RenameField",
|
||||
"RenameField",
|
||||
"AddConstraint",
|
||||
],
|
||||
)
|
||||
|
||||
def test_rename_field_with_renamed_model(self):
|
||||
changes = self.get_changes(
|
||||
[self.author_name],
|
||||
|
Loading…
x
Reference in New Issue
Block a user