From b1cbbe926789bcfc2e118c7d7c7a0f30fab5248a Mon Sep 17 00:00:00 2001 From: Simon Charette Date: Tue, 24 May 2016 15:38:01 -0400 Subject: [PATCH] Refs #25530 -- Deleted deferred SQL references on delete operation. --- django/db/backends/base/schema.py | 8 ++++++++ django/db/backends/sqlite3/schema.py | 9 ++++----- tests/schema/tests.py | 22 +++++++++++++++++----- 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/django/db/backends/base/schema.py b/django/db/backends/base/schema.py index e31251ae81..91ee3dac22 100644 --- a/django/db/backends/base/schema.py +++ b/django/db/backends/base/schema.py @@ -314,6 +314,10 @@ class BaseDatabaseSchemaEditor: self.execute(self.sql_delete_table % { "table": self.quote_name(model._meta.db_table), }) + # Remove all deferred statements referencing the deleted table. + for sql in list(self.deferred_sql): + if isinstance(sql, Statement) and sql.references_table(model._meta.db_table): + self.deferred_sql.remove(sql) def add_index(self, model, index): """Add an index on a model.""" @@ -456,6 +460,10 @@ class BaseDatabaseSchemaEditor: # Reset connection if required if self.connection.features.connection_persists_old_columns: self.connection.close() + # Remove all deferred statements referencing the deleted table. + for sql in list(self.deferred_sql): + if isinstance(sql, Statement) and sql.references_column(model._meta.db_table, field.column): + self.deferred_sql.remove(sql) def alter_field(self, model, old_field, new_field, strict=False): """ diff --git a/django/db/backends/sqlite3/schema.py b/django/db/backends/sqlite3/schema.py index 5517d78a97..3bf71e071a 100644 --- a/django/db/backends/sqlite3/schema.py +++ b/django/db/backends/sqlite3/schema.py @@ -190,11 +190,6 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor): # Rename the old table to make way for the new self.alter_db_table(model, temp_model._meta.db_table, model._meta.db_table) - # Remove all deferred statements referencing the temporary table. - for sql in list(self.deferred_sql): - if isinstance(sql, Statement) and sql.references_table(temp_model._meta.db_table): - self.deferred_sql.remove(sql) - # Create a new table with the updated schema. self.create_model(temp_model) @@ -226,6 +221,10 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor): self.execute(self.sql_delete_table % { "table": self.quote_name(model._meta.db_table), }) + # Remove all deferred statements referencing the deleted table. + for sql in list(self.deferred_sql): + if isinstance(sql, Statement) and sql.references_table(model._meta.db_table): + self.deferred_sql.remove(sql) def add_field(self, model, field): """ diff --git a/tests/schema/tests.py b/tests/schema/tests.py index f4612a5dee..b889f6cda1 100644 --- a/tests/schema/tests.py +++ b/tests/schema/tests.py @@ -195,14 +195,15 @@ class SchemaTests(TransactionTestCase): """ Tries creating a model's table, and then deleting it. """ - # Create the table with connection.schema_editor() as editor: + # Create the table editor.create_model(Author) - # The table is there - list(Author.objects.all()) - # Clean up that table - with connection.schema_editor() as editor: + # The table is there + list(Author.objects.all()) + # Clean up that table editor.delete_model(Author) + # No deferred SQL should be left over. + self.assertEqual(editor.deferred_sql, []) # The table is gone with self.assertRaises(DatabaseError): list(Author.objects.all()) @@ -379,6 +380,17 @@ class SchemaTests(TransactionTestCase): self.assertEqual(columns['age'][0], "IntegerField") self.assertEqual(columns['age'][1][6], True) + def test_add_field_remove_field(self): + """ + Adding a field and removing it removes all deferred sql referring to it. + """ + with connection.schema_editor() as editor: + # Create a table with a unique constraint on the slug field. + editor.create_model(Tag) + # Remove the slug column. + editor.remove_field(Tag, Tag._meta.get_field('slug')) + self.assertEqual(editor.deferred_sql, []) + def test_add_field_temp_default(self): """ Tests adding fields to models with a temporary default