mirror of
https://github.com/django/django.git
synced 2025-06-27 22:39:12 +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:
|
for attr in new_constraint.non_db_attrs:
|
||||||
new_kwargs.pop(attr, None)
|
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)
|
return (old_path, old_args, old_kwargs) != (new_path, new_args, new_kwargs)
|
||||||
|
|
||||||
def create_altered_constraints(self):
|
def create_altered_constraints(self):
|
||||||
|
@ -2078,6 +2078,186 @@ class AutodetectorTests(BaseAutodetectorTests):
|
|||||||
new_name="renamed_foo",
|
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):
|
def test_rename_field_with_renamed_model(self):
|
||||||
changes = self.get_changes(
|
changes = self.get_changes(
|
||||||
[self.author_name],
|
[self.author_name],
|
||||||
|
Loading…
x
Reference in New Issue
Block a user