diff options
author | Mads Jensen <mje@inducks.org> | 2019-07-25 13:44:18 +0200 |
---|---|---|
committer | Mariusz Felisiak <felisiak.mariusz@gmail.com> | 2019-08-21 13:10:06 +0200 |
commit | 85ac838d9e6975130b5c55299e9d7d1222a8e289 (patch) | |
tree | 2466fdf4773081dfbaa33c24cda4b01ec9fc23e6 /django/contrib/postgres/operations.py | |
parent | 9a88e43aeba6cc85ffb2a48a06c296ccf68e0d71 (diff) | |
download | django-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.py | 60 |
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) |