fix: resolve migration transaction issue with CONCURRENTLY

- Detect transaction context using connection.in_atomic_block
- Use regular CREATE INDEX when in transaction (test environment)
- Use CREATE INDEX CONCURRENTLY when not in transaction (production)
- Maintains production safety while fixing CI test failures
- All 8 indexes now create successfully in both environments

Fixes CI error: 'CREATE INDEX CONCURRENTLY cannot run inside a transaction block'
This commit is contained in:
Oliver Falk
2025-10-15 17:17:38 +02:00
parent 23c36604b8
commit b4598212e5

View File

@@ -8,7 +8,7 @@ from django.db import migrations, connection
def create_indexes(apps: Any, schema_editor: Any) -> None: def create_indexes(apps: Any, schema_editor: Any) -> None:
""" """
Create performance indexes for both PostgreSQL and MySQL compatibility. Create performance indexes for both PostgreSQL and MySQL compatibility.
Uses CONCURRENTLY for PostgreSQL and regular CREATE INDEX for MySQL. Uses CONCURRENTLY for PostgreSQL production, regular CREATE INDEX for tests/transactions.
""" """
db_engine = connection.vendor db_engine = connection.vendor
@@ -53,10 +53,26 @@ def create_indexes(apps: Any, schema_editor: Any) -> None:
] ]
with connection.cursor() as cursor: with connection.cursor() as cursor:
# Check if we're in a transaction (test environment)
try:
cursor.execute("SELECT 1")
in_transaction = connection.in_atomic_block
except Exception:
in_transaction = True
for index_name, table_name, columns, where_clause in indexes: for index_name, table_name, columns, where_clause in indexes:
try: try:
if db_engine == "postgresql": if db_engine == "postgresql":
# PostgreSQL with CONCURRENTLY for production safety # Use CONCURRENTLY only if not in a transaction (production)
# Use regular CREATE INDEX if in a transaction (tests)
if in_transaction:
# In transaction (test environment) - use regular CREATE INDEX
if where_clause:
sql = f"CREATE INDEX IF NOT EXISTS {index_name} ON {table_name}({columns}) {where_clause};"
else:
sql = f"CREATE INDEX IF NOT EXISTS {index_name} ON {table_name}({columns});"
else:
# Not in transaction (production) - use CONCURRENTLY
if where_clause: if where_clause:
sql = f"CREATE INDEX CONCURRENTLY IF NOT EXISTS {index_name} ON {table_name}({columns}) {where_clause};" sql = f"CREATE INDEX CONCURRENTLY IF NOT EXISTS {index_name} ON {table_name}({columns}) {where_clause};"
else: else: