summaryrefslogtreecommitdiff
path: root/django/contrib/postgres/operations.py
diff options
context:
space:
mode:
authorMads Jensen <mje@inducks.org>2019-07-25 13:44:18 +0200
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2019-08-21 13:10:06 +0200
commit85ac838d9e6975130b5c55299e9d7d1222a8e289 (patch)
tree2466fdf4773081dfbaa33c24cda4b01ec9fc23e6 /django/contrib/postgres/operations.py
parent9a88e43aeba6cc85ffb2a48a06c296ccf68e0d71 (diff)
downloaddjango-85ac838d9e6975130b5c55299e9d7d1222a8e289.tar.gz
Fixed #21039 -- Added AddIndexConcurrently/RemoveIndexConcurrently operations for PostgreSQL.
Thanks to Simon Charettes for review. Co-Authored-By: Daniel Tao <daniel.tao@gmail.com>
Diffstat (limited to 'django/contrib/postgres/operations.py')
-rw-r--r--django/contrib/postgres/operations.py60
1 files changed, 60 insertions, 0 deletions
diff --git a/django/contrib/postgres/operations.py b/django/contrib/postgres/operations.py
index 95e7edcdea..9e417725ec 100644
--- a/django/contrib/postgres/operations.py
+++ b/django/contrib/postgres/operations.py
@@ -1,7 +1,9 @@
from django.contrib.postgres.signals import (
get_citext_oids, get_hstore_oids, register_type_handlers,
)
+from django.db.migrations import AddIndex, RemoveIndex
from django.db.migrations.operations.base import Operation
+from django.db.utils import NotSupportedError
class CreateExtension(Operation):
@@ -75,3 +77,61 @@ class UnaccentExtension(CreateExtension):
def __init__(self):
self.name = 'unaccent'
+
+
+class NotInTransactionMixin:
+ def _ensure_not_in_transaction(self, schema_editor):
+ if schema_editor.connection.in_atomic_block:
+ raise NotSupportedError(
+ 'The %s operation cannot be executed inside a transaction '
+ '(set atomic = False on the migration).'
+ % self.__class__.__name__
+ )
+
+
+class AddIndexConcurrently(NotInTransactionMixin, AddIndex):
+ """Create an index using PostgreSQL's CREATE INDEX CONCURRENTLY syntax."""
+ atomic = False
+
+ def describe(self):
+ return 'Concurrently create index %s on field(s) %s of model %s' % (
+ self.index.name,
+ ', '.join(self.index.fields),
+ self.model_name,
+ )
+
+ def database_forwards(self, app_label, schema_editor, from_state, to_state):
+ self._ensure_not_in_transaction(schema_editor)
+ model = to_state.apps.get_model(app_label, self.model_name)
+ if self.allow_migrate_model(schema_editor.connection.alias, model):
+ schema_editor.add_index(model, self.index, concurrently=True)
+
+ def database_backwards(self, app_label, schema_editor, from_state, to_state):
+ self._ensure_not_in_transaction(schema_editor)
+ model = from_state.apps.get_model(app_label, self.model_name)
+ if self.allow_migrate_model(schema_editor.connection.alias, model):
+ schema_editor.remove_index(model, self.index, concurrently=True)
+
+
+class RemoveIndexConcurrently(NotInTransactionMixin, RemoveIndex):
+ """Remove an index using PostgreSQL's DROP INDEX CONCURRENTLY syntax."""
+ atomic = False
+
+ def describe(self):
+ return 'Concurrently remove index %s from %s' % (self.name, self.model_name)
+
+ def database_forwards(self, app_label, schema_editor, from_state, to_state):
+ self._ensure_not_in_transaction(schema_editor)
+ model = from_state.apps.get_model(app_label, self.model_name)
+ if self.allow_migrate_model(schema_editor.connection.alias, model):
+ from_model_state = from_state.models[app_label, self.model_name_lower]
+ index = from_model_state.get_index_by_name(self.name)
+ schema_editor.remove_index(model, index, concurrently=True)
+
+ def database_backwards(self, app_label, schema_editor, from_state, to_state):
+ self._ensure_not_in_transaction(schema_editor)
+ model = to_state.apps.get_model(app_label, self.model_name)
+ if self.allow_migrate_model(schema_editor.connection.alias, model):
+ to_model_state = to_state.models[app_label, self.model_name_lower]
+ index = to_model_state.get_index_by_name(self.name)
+ schema_editor.add_index(model, index, concurrently=True)