summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Charette <charette.s@gmail.com>2021-01-20 19:00:36 -0500
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2021-01-21 07:03:35 +0100
commit0c42cdf0d2422f4c080e93594d5d15381d6e955e (patch)
tree6403efc1a2b35c548b174165fd14e16c9d99396c
parent533a5835784b95335c8373b6d0b9495b3834e96e (diff)
Fixed #32374 -- Stopped recording migration application before deferred SQL.
Migrations cannot be recorded in the same transaction as its associated DDL operations when some of it is deferred until the schema editor context exits. Regression in c86a3d80a25acd1887319198ca21a84c451014ad.
-rw-r--r--django/db/migrations/executor.py5
-rw-r--r--tests/migrations/test_executor.py27
2 files changed, 30 insertions, 2 deletions
diff --git a/django/db/migrations/executor.py b/django/db/migrations/executor.py
index 83d624e08a..57042a8690 100644
--- a/django/db/migrations/executor.py
+++ b/django/db/migrations/executor.py
@@ -225,8 +225,9 @@ class MigrationExecutor:
# Alright, do it normally
with self.connection.schema_editor(atomic=migration.atomic) as schema_editor:
state = migration.apply(state, schema_editor)
- self.record_migration(migration)
- migration_recorded = True
+ if not schema_editor.deferred_sql:
+ self.record_migration(migration)
+ migration_recorded = True
if not migration_recorded:
self.record_migration(migration)
# Report progress
diff --git a/tests/migrations/test_executor.py b/tests/migrations/test_executor.py
index 8cab8732c4..e61d8f1276 100644
--- a/tests/migrations/test_executor.py
+++ b/tests/migrations/test_executor.py
@@ -684,6 +684,33 @@ class ExecutorTests(MigrationTestBase):
)
self.assertTableNotExists('record_migration_model')
+ def test_migrations_not_applied_on_deferred_sql_failure(self):
+ """Migrations are not recorded if deferred SQL application fails."""
+ class DeferredSQL:
+ def __str__(self):
+ raise DatabaseError('Failed to apply deferred SQL')
+
+ class Migration(migrations.Migration):
+ atomic = False
+
+ def apply(self, project_state, schema_editor, collect_sql=False):
+ schema_editor.deferred_sql.append(DeferredSQL())
+
+ executor = MigrationExecutor(connection)
+ with self.assertRaisesMessage(DatabaseError, 'Failed to apply deferred SQL'):
+ executor.apply_migration(
+ ProjectState(),
+ Migration('0001_initial', 'deferred_sql'),
+ )
+ # The migration isn't recorded as applied since it failed.
+ migration_recorder = MigrationRecorder(connection)
+ self.assertIs(
+ migration_recorder.migration_qs.filter(
+ app='deferred_sql', name='0001_initial',
+ ).exists(),
+ False,
+ )
+
class FakeLoader:
def __init__(self, graph, applied):