mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	Fixed #31106 -- Fixed migrations crash on PostgreSQL 10+ when adding FK constraints inline and changing data.
This allows adding foreign key constraints inline and changing data in
the same migration on PostgreSQL 10+.
Regression in 738faf9da2.
Thanks Janne Rönkkö for the report and Simon Charette for the
implementation idea and review.
			
			
This commit is contained in:
		| @@ -19,7 +19,12 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor): | ||||
|     sql_delete_index = "DROP INDEX IF EXISTS %(name)s" | ||||
|     sql_delete_index_concurrently = "DROP INDEX CONCURRENTLY IF EXISTS %(name)s" | ||||
|  | ||||
|     sql_create_column_inline_fk = 'REFERENCES %(to_table)s(%(to_column)s)%(deferrable)s' | ||||
|     # Setting the constraint to IMMEDIATE to allow changing data in the same | ||||
|     # transaction. | ||||
|     sql_create_column_inline_fk = ( | ||||
|         'CONSTRAINT %(name)s REFERENCES %(to_table)s(%(to_column)s)%(deferrable)s' | ||||
|         '; SET CONSTRAINTS %(name)s IMMEDIATE' | ||||
|     ) | ||||
|     # Setting the constraint to IMMEDIATE runs any deferred checks to allow | ||||
|     # dropping it in the same transaction. | ||||
|     sql_delete_fk = "SET CONSTRAINTS %(name)s IMMEDIATE; ALTER TABLE %(table)s DROP CONSTRAINT %(name)s" | ||||
|   | ||||
| @@ -14,3 +14,7 @@ Bugfixes | ||||
|  | ||||
| * Fixed a regression in Django 3.0 where ``QuerySet.exists()`` crashed if a | ||||
|   queryset contained an aggregation over a ``Subquery()`` (:ticket:`31109`). | ||||
|  | ||||
| * Fixed a regression in Django 3.0 that caused a migration crash on PostgreSQL | ||||
|   10+ when adding a foreign key and changing data in the same migration | ||||
|   (:ticket:`31106`). | ||||
|   | ||||
| @@ -275,6 +275,43 @@ class SchemaTests(TransactionTestCase): | ||||
|             if sql.startswith('ALTER TABLE') and 'ADD CONSTRAINT' in sql | ||||
|         ]) | ||||
|  | ||||
|     @skipUnlessDBFeature('can_create_inline_fk') | ||||
|     def test_add_inline_fk_update_data(self): | ||||
|         with connection.schema_editor() as editor: | ||||
|             editor.create_model(Node) | ||||
|         # Add an inline foreign key and update data in the same transaction. | ||||
|         new_field = ForeignKey(Node, CASCADE, related_name='new_fk', null=True) | ||||
|         new_field.set_attributes_from_name('new_parent_fk') | ||||
|         parent = Node.objects.create() | ||||
|         with connection.schema_editor() as editor: | ||||
|             editor.add_field(Node, new_field) | ||||
|             editor.execute('UPDATE schema_node SET new_parent_fk_id = %s;', [parent.pk]) | ||||
|         self.assertIn('new_parent_fk_id', self.get_indexes(Node._meta.db_table)) | ||||
|  | ||||
|     @skipUnlessDBFeature( | ||||
|         'can_create_inline_fk', | ||||
|         'allows_multiple_constraints_on_same_fields', | ||||
|     ) | ||||
|     @isolate_apps('schema') | ||||
|     def test_add_inline_fk_index_update_data(self): | ||||
|         class Node(Model): | ||||
|             class Meta: | ||||
|                 app_label = 'schema' | ||||
|  | ||||
|         with connection.schema_editor() as editor: | ||||
|             editor.create_model(Node) | ||||
|         # Add an inline foreign key, update data, and an index in the same | ||||
|         # transaction. | ||||
|         new_field = ForeignKey(Node, CASCADE, related_name='new_fk', null=True) | ||||
|         new_field.set_attributes_from_name('new_parent_fk') | ||||
|         parent = Node.objects.create() | ||||
|         with connection.schema_editor() as editor: | ||||
|             editor.add_field(Node, new_field) | ||||
|             Node._meta.add_field(new_field) | ||||
|             editor.execute('UPDATE schema_node SET new_parent_fk_id = %s;', [parent.pk]) | ||||
|             editor.add_index(Node, Index(fields=['new_parent_fk'], name='new_parent_inline_fk_idx')) | ||||
|         self.assertIn('new_parent_fk_id', self.get_indexes(Node._meta.db_table)) | ||||
|  | ||||
|     @skipUnlessDBFeature('supports_foreign_keys') | ||||
|     def test_char_field_with_db_index_to_fk(self): | ||||
|         # Create the table | ||||
|   | ||||
		Reference in New Issue
	
	Block a user