diff options
| author | Clifford Gama <cliffygamy@gmail.com> | 2025-07-05 12:47:53 +0200 |
|---|---|---|
| committer | Sarah Boyce <42296566+sarahboyce@users.noreply.github.com> | 2025-07-25 13:59:13 +0200 |
| commit | 1a7fc0f65d5b2ef56625a8b5897496e28a5834ff (patch) | |
| tree | f46b1d042f0d375ea0d599572a55092d3a67dbf4 /tests/migrations | |
| parent | 9ab1991689000821a4d86b8617e1c1455a327482 (diff) | |
Fixed #36438 -- Made MigrationAutodetector remove generated fields before their base fields.
Thanks to Colton Saska for the report and to Simon Charette for the review.
Diffstat (limited to 'tests/migrations')
| -rw-r--r-- | tests/migrations/test_autodetector.py | 96 |
1 files changed, 95 insertions, 1 deletions
diff --git a/tests/migrations/test_autodetector.py b/tests/migrations/test_autodetector.py index c5d630293e..c044cc9a99 100644 --- a/tests/migrations/test_autodetector.py +++ b/tests/migrations/test_autodetector.py @@ -13,7 +13,7 @@ from django.db.migrations.graph import MigrationGraph from django.db.migrations.loader import MigrationLoader from django.db.migrations.questioner import MigrationQuestioner from django.db.migrations.state import ModelState, ProjectState -from django.db.models.functions import Concat, Lower +from django.db.models.functions import Concat, Lower, Upper from django.test import SimpleTestCase, TestCase, override_settings from django.test.utils import isolate_lru_cache @@ -1454,6 +1454,100 @@ class AutodetectorTests(BaseAutodetectorTests): self.assertOperationTypes(changes, "testapp", 0, ["RemoveField"]) self.assertOperationAttributes(changes, "testapp", 0, 0, name="name") + def test_remove_generated_field_before_its_base_field(self): + initial_state = [ + ModelState( + "testapp", + "Author", + [ + ("name", models.CharField(max_length=20)), + ( + "upper_name", + models.GeneratedField( + expression=Upper("name"), + db_persist=True, + output_field=models.CharField(), + ), + ), + ], + ), + ] + updated_state = [ModelState("testapp", "Author", [])] + changes = self.get_changes(initial_state, updated_state) + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes(changes, "testapp", 0, ["RemoveField", "RemoveField"]) + self.assertOperationAttributes(changes, "testapp", 0, 0, name="upper_name") + self.assertOperationAttributes(changes, "testapp", 0, 1, name="name") + + def test_remove_generated_field_before_multiple_base_fields(self): + initial_state = [ + ModelState( + "testapp", + "Author", + [ + ("first_name", models.CharField(max_length=20)), + ("last_name", models.CharField(max_length=20)), + ( + "full_name", + models.GeneratedField( + expression=Concat("first_name", "last_name"), + db_persist=True, + output_field=models.CharField(), + ), + ), + ], + ), + ] + updated_state = [ModelState("testapp", "Author", [])] + changes = self.get_changes(initial_state, updated_state) + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes( + changes, "testapp", 0, ["RemoveField", "RemoveField", "RemoveField"] + ) + self.assertOperationAttributes(changes, "testapp", 0, 0, name="full_name") + self.assertOperationAttributes(changes, "testapp", 0, 1, name="first_name") + self.assertOperationAttributes(changes, "testapp", 0, 2, name="last_name") + + def test_remove_generated_field_and_one_of_multiple_base_fields(self): + initial_state = [ + ModelState( + "testapp", + "Author", + [ + ("first_name", models.CharField(max_length=20)), + ("last_name", models.CharField(max_length=20)), + ( + "full_name", + models.GeneratedField( + expression=Concat("first_name", "last_name"), + db_persist=True, + output_field=models.CharField(), + ), + ), + ], + ), + ] + # Only remove full_name and first_name. + updated_state = [ + ModelState( + "testapp", + "Author", + [ + ("last_name", models.CharField(max_length=20)), + ], + ), + ] + changes = self.get_changes(initial_state, updated_state) + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes( + changes, + "testapp", + 0, + ["RemoveField", "RemoveField"], + ) + self.assertOperationAttributes(changes, "testapp", 0, 0, name="full_name") + self.assertOperationAttributes(changes, "testapp", 0, 1, name="first_name") + def test_alter_field(self): """Tests autodetection of new fields.""" changes = self.get_changes([self.author_name], [self.author_name_longer]) |
