mirror of
				https://github.com/django/django.git
				synced 2025-10-30 17:16:10 +00:00 
			
		
		
		
	[1.7.x] Fixed #23101: Prefer doing deletes before creates in autodetector.
Makes declined or missed renames still work (but drop data).
This commit is contained in:
		| @@ -160,15 +160,16 @@ class MigrationAutodetector(object): | |||||||
|                     self.through_users[through_key] = (app_label, old_model_name, field_name) |                     self.through_users[through_key] = (app_label, old_model_name, field_name) | ||||||
|  |  | ||||||
|         # Generate non-rename model operations |         # Generate non-rename model operations | ||||||
|         self.generate_created_models() |  | ||||||
|         self.generate_deleted_models() |         self.generate_deleted_models() | ||||||
|         self.generate_created_proxies() |         self.generate_created_models() | ||||||
|         self.generate_deleted_proxies() |         self.generate_deleted_proxies() | ||||||
|  |         self.generate_created_proxies() | ||||||
|         self.generate_altered_options() |         self.generate_altered_options() | ||||||
|  |  | ||||||
|         # Generate field operations |         # Generate field operations | ||||||
|         self.generate_added_fields() |         self.generate_renamed_fields() | ||||||
|         self.generate_removed_fields() |         self.generate_removed_fields() | ||||||
|  |         self.generate_added_fields() | ||||||
|         self.generate_altered_fields() |         self.generate_altered_fields() | ||||||
|         self.generate_altered_unique_together() |         self.generate_altered_unique_together() | ||||||
|         self.generate_altered_index_together() |         self.generate_altered_index_together() | ||||||
| @@ -682,17 +683,17 @@ class MigrationAutodetector(object): | |||||||
|                 ), |                 ), | ||||||
|             ) |             ) | ||||||
|  |  | ||||||
|     def generate_added_fields(self): |     def generate_renamed_fields(self): | ||||||
|         # New fields |         """ | ||||||
|  |         Works out renamed fields | ||||||
|  |         """ | ||||||
|         self.renamed_fields = {} |         self.renamed_fields = {} | ||||||
|         for app_label, model_name, field_name in sorted(self.new_field_keys - self.old_field_keys): |         for app_label, model_name, field_name in sorted(self.new_field_keys - self.old_field_keys): | ||||||
|             old_model_name = self.renamed_models.get((app_label, model_name), model_name) |             old_model_name = self.renamed_models.get((app_label, model_name), model_name) | ||||||
|             old_model_state = self.from_state.models[app_label, old_model_name] |             old_model_state = self.from_state.models[app_label, old_model_name] | ||||||
|             new_model_state = self.to_state.models[app_label, model_name] |  | ||||||
|             field = self.new_apps.get_model(app_label, model_name)._meta.get_field_by_name(field_name)[0] |             field = self.new_apps.get_model(app_label, model_name)._meta.get_field_by_name(field_name)[0] | ||||||
|             # Scan to see if this is actually a rename! |             # Scan to see if this is actually a rename! | ||||||
|             field_dec = self.deep_deconstruct(field) |             field_dec = self.deep_deconstruct(field) | ||||||
|             found_rename = False |  | ||||||
|             for rem_app_label, rem_model_name, rem_field_name in sorted(self.old_field_keys - self.new_field_keys): |             for rem_app_label, rem_model_name, rem_field_name in sorted(self.old_field_keys - self.new_field_keys): | ||||||
|                 if rem_app_label == app_label and rem_model_name == model_name: |                 if rem_app_label == app_label and rem_model_name == model_name: | ||||||
|                     old_field_dec = self.deep_deconstruct(old_model_state.get_field_by_name(rem_field_name)) |                     old_field_dec = self.deep_deconstruct(old_model_state.get_field_by_name(rem_field_name)) | ||||||
| @@ -713,10 +714,15 @@ class MigrationAutodetector(object): | |||||||
|                             self.old_field_keys.remove((rem_app_label, rem_model_name, rem_field_name)) |                             self.old_field_keys.remove((rem_app_label, rem_model_name, rem_field_name)) | ||||||
|                             self.old_field_keys.add((app_label, model_name, field_name)) |                             self.old_field_keys.add((app_label, model_name, field_name)) | ||||||
|                             self.renamed_fields[app_label, model_name, field_name] = rem_field_name |                             self.renamed_fields[app_label, model_name, field_name] = rem_field_name | ||||||
|                             found_rename = True |  | ||||||
|                             break |                             break | ||||||
|             if found_rename: |  | ||||||
|                 continue |  | ||||||
|  |     def generate_added_fields(self): | ||||||
|  |         """ | ||||||
|  |         Fields that have been added | ||||||
|  |         """ | ||||||
|  |         for app_label, model_name, field_name in sorted(self.new_field_keys - self.old_field_keys): | ||||||
|  |             field = self.new_apps.get_model(app_label, model_name)._meta.get_field_by_name(field_name)[0] | ||||||
|             # Fields that are foreignkeys/m2ms depend on stuff |             # Fields that are foreignkeys/m2ms depend on stuff | ||||||
|             dependencies = [] |             dependencies = [] | ||||||
|             if field.rel and field.rel.to: |             if field.rel and field.rel.to: | ||||||
|   | |||||||
| @@ -276,16 +276,10 @@ class AutodetectorTests(TestCase): | |||||||
|         after = self.make_project_state([self.author_name_renamed]) |         after = self.make_project_state([self.author_name_renamed]) | ||||||
|         autodetector = MigrationAutodetector(before, after, MigrationQuestioner({"ask_rename": True})) |         autodetector = MigrationAutodetector(before, after, MigrationQuestioner({"ask_rename": True})) | ||||||
|         changes = autodetector._detect_changes() |         changes = autodetector._detect_changes() | ||||||
|         # Right number of migrations? |         # Check | ||||||
|         self.assertEqual(len(changes['testapp']), 1) |         self.assertNumberMigrations(changes, 'testapp', 1) | ||||||
|         # Right number of actions? |         self.assertOperationTypes(changes, 'testapp', 0, ["RenameField"]) | ||||||
|         migration = changes['testapp'][0] |         self.assertOperationAttributes(changes, 'testapp', 0, 0, old_name="name", new_name="names") | ||||||
|         self.assertEqual(len(migration.operations), 1) |  | ||||||
|         # Right action? |  | ||||||
|         action = migration.operations[0] |  | ||||||
|         self.assertEqual(action.__class__.__name__, "RenameField") |  | ||||||
|         self.assertEqual(action.old_name, "name") |  | ||||||
|         self.assertEqual(action.new_name, "names") |  | ||||||
|  |  | ||||||
|     def test_rename_model(self): |     def test_rename_model(self): | ||||||
|         "Tests autodetection of renamed models" |         "Tests autodetection of renamed models" | ||||||
| @@ -719,21 +713,12 @@ class AutodetectorTests(TestCase): | |||||||
|         after = self.make_project_state([self.author_with_publisher, self.publisher]) |         after = self.make_project_state([self.author_with_publisher, self.publisher]) | ||||||
|         autodetector = MigrationAutodetector(before, after) |         autodetector = MigrationAutodetector(before, after) | ||||||
|         changes = autodetector._detect_changes() |         changes = autodetector._detect_changes() | ||||||
|         # Right number of migrations? |         # Right result? | ||||||
|         self.assertEqual(len(changes['testapp']), 1) |         self.assertNumberMigrations(changes, 'testapp', 1) | ||||||
|         # Right number of actions? |         self.assertOperationTypes(changes, 'testapp', 0, ["CreateModel", "RemoveField", "AddField"]) | ||||||
|         migration = changes['testapp'][0] |         self.assertOperationAttributes(changes, 'testapp', 0, 0, name="Publisher") | ||||||
|         self.assertEqual(len(migration.operations), 3) |         self.assertOperationAttributes(changes, 'testapp', 0, 1, name="publisher_name") | ||||||
|         # Right actions? |         self.assertOperationAttributes(changes, 'testapp', 0, 2, name="publisher") | ||||||
|         action = migration.operations[0] |  | ||||||
|         self.assertEqual(action.__class__.__name__, "CreateModel") |  | ||||||
|         self.assertEqual(action.name, "Publisher") |  | ||||||
|         action = migration.operations[1] |  | ||||||
|         self.assertEqual(action.__class__.__name__, "AddField") |  | ||||||
|         self.assertEqual(action.name, "publisher") |  | ||||||
|         action = migration.operations[2] |  | ||||||
|         self.assertEqual(action.__class__.__name__, "RemoveField") |  | ||||||
|         self.assertEqual(action.name, "publisher_name") |  | ||||||
|  |  | ||||||
|     def test_foreign_key_removed_before_target_model(self): |     def test_foreign_key_removed_before_target_model(self): | ||||||
|         """ |         """ | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user