summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAkshesh <aksheshdoshi@gmail.com>2016-08-08 17:20:25 +0530
committerTim Graham <timograham@gmail.com>2016-08-12 18:37:03 -0400
commit6e07ec3f655073bebdf1b1dfd2303e91202e14e1 (patch)
treed62f91ee2af2a9ae218087037f76d48767ebac35
parent236baa0f0ec31422bc8c36b24e41112f7a564532 (diff)
Fixed #27030 -- Added contrib.postgres.indexes.GinIndex.
-rw-r--r--django/contrib/postgres/indexes.py12
-rw-r--r--django/db/backends/base/schema.py1
-rw-r--r--django/db/backends/postgresql/schema.py1
-rw-r--r--django/db/models/indexes.py3
-rw-r--r--docs/ref/contrib/postgres/index.txt1
-rw-r--r--docs/ref/contrib/postgres/indexes.txt24
-rw-r--r--docs/ref/models/indexes.txt5
-rw-r--r--tests/postgres_tests/test_indexes.py55
-rw-r--r--tests/schema/tests.py1
9 files changed, 102 insertions, 1 deletions
diff --git a/django/contrib/postgres/indexes.py b/django/contrib/postgres/indexes.py
new file mode 100644
index 0000000000..5382c15e1a
--- /dev/null
+++ b/django/contrib/postgres/indexes.py
@@ -0,0 +1,12 @@
+from __future__ import unicode_literals
+
+from django.db.models import Index
+
+__all__ = ['GinIndex']
+
+
+class GinIndex(Index):
+ suffix = 'gin'
+
+ def create_sql(self, model, schema_editor):
+ return super(GinIndex, self).create_sql(model, schema_editor, using=' USING gin')
diff --git a/django/db/backends/base/schema.py b/django/db/backends/base/schema.py
index 67960a02ac..aae64e3be7 100644
--- a/django/db/backends/base/schema.py
+++ b/django/db/backends/base/schema.py
@@ -880,6 +880,7 @@ class BaseDatabaseSchemaEditor(object):
return sql_create_index % {
"table": self.quote_name(model._meta.db_table),
"name": self.quote_name(self._create_index_name(model, columns, suffix=suffix)),
+ "using": "",
"columns": ", ".join(self.quote_name(column) for column in columns),
"extra": tablespace_sql,
}
diff --git a/django/db/backends/postgresql/schema.py b/django/db/backends/postgresql/schema.py
index 16f2003196..1afb85d468 100644
--- a/django/db/backends/postgresql/schema.py
+++ b/django/db/backends/postgresql/schema.py
@@ -11,6 +11,7 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
sql_delete_sequence = "DROP SEQUENCE IF EXISTS %(sequence)s CASCADE"
sql_set_sequence_max = "SELECT setval('%(sequence)s', MAX(%(column)s)) FROM %(table)s"
+ sql_create_index = "CREATE INDEX %(name)s ON %(table)s%(using)s (%(columns)s)%(extra)s"
sql_create_varchar_index = "CREATE INDEX %(name)s ON %(table)s (%(columns)s varchar_pattern_ops)%(extra)s"
sql_create_text_index = "CREATE INDEX %(name)s ON %(table)s (%(columns)s text_pattern_ops)%(extra)s"
diff --git a/django/db/models/indexes.py b/django/db/models/indexes.py
index bb33f8a758..f70c2e5625 100644
--- a/django/db/models/indexes.py
+++ b/django/db/models/indexes.py
@@ -42,7 +42,7 @@ class Index(object):
self.name = 'D%s' % self.name[1:]
return errors
- def create_sql(self, model, schema_editor):
+ def create_sql(self, model, schema_editor, using=''):
fields = [model._meta.get_field(field_name) for field_name, order in self.fields_orders]
tablespace_sql = schema_editor._get_index_tablespace_sql(model, fields)
quote_name = schema_editor.quote_name
@@ -54,6 +54,7 @@ class Index(object):
'table': quote_name(model._meta.db_table),
'name': quote_name(self.name),
'columns': ', '.join(columns),
+ 'using': using,
'extra': tablespace_sql,
}
diff --git a/docs/ref/contrib/postgres/index.txt b/docs/ref/contrib/postgres/index.txt
index d04ed14889..5a212fbdcd 100644
--- a/docs/ref/contrib/postgres/index.txt
+++ b/docs/ref/contrib/postgres/index.txt
@@ -35,6 +35,7 @@ release. Some fields require higher versions.
fields
forms
functions
+ indexes
lookups
operations
search
diff --git a/docs/ref/contrib/postgres/indexes.txt b/docs/ref/contrib/postgres/indexes.txt
new file mode 100644
index 0000000000..7bf26fb117
--- /dev/null
+++ b/docs/ref/contrib/postgres/indexes.txt
@@ -0,0 +1,24 @@
+=================================
+PostgreSQL specific model indexes
+=================================
+
+.. module:: django.contrib.postgres.indexes
+
+.. versionadded:: 1.11
+
+The following are PostgreSQL specific :doc:`indexes </ref/models/indexes>`
+available from the ``django.contrib.postgres.indexes`` module.
+
+``GinIndex``
+============
+
+.. class:: GinIndex()
+
+ Creates a `gin index
+ <https://www.postgresql.org/docs/current/static/gin.html>`_.
+
+ To use this index, you need to activate the `btree_gin extension
+ <https://www.postgresql.org/docs/current/static/btree-gin.html>`_ on
+ PostgreSQL. You can install it using the
+ :class:`~django.contrib.postgres.operations.BtreeGinExtension` migration
+ operation.
diff --git a/docs/ref/models/indexes.txt b/docs/ref/models/indexes.txt
index ac2839bbd4..999513c9d6 100644
--- a/docs/ref/models/indexes.txt
+++ b/docs/ref/models/indexes.txt
@@ -56,3 +56,8 @@ case, a descending index is created as a normal index.
The name of the index. If ``name`` isn't provided Django will auto-generate a
name. For compatibility with different databases, index names cannot be longer
than 30 characters and shouldn't start with a number (0-9) or underscore (_).
+
+.. seealso::
+
+ For a list of PostgreSQL-specific indexes, see
+ :mod:`django.contrib.postgres.indexes`.
diff --git a/tests/postgres_tests/test_indexes.py b/tests/postgres_tests/test_indexes.py
new file mode 100644
index 0000000000..41bdd3beca
--- /dev/null
+++ b/tests/postgres_tests/test_indexes.py
@@ -0,0 +1,55 @@
+from django.contrib.postgres.indexes import GinIndex
+from django.db import connection
+
+from . import PostgreSQLTestCase
+from .models import IntegerArrayModel
+
+
+class GinIndexTests(PostgreSQLTestCase):
+
+ def test_repr(self):
+ index = GinIndex(fields=['title'])
+ self.assertEqual(repr(index), "<GinIndex: fields='title'>")
+
+ def test_eq(self):
+ index = GinIndex(fields=['title'])
+ same_index = GinIndex(fields=['title'])
+ another_index = GinIndex(fields=['author'])
+ self.assertEqual(index, same_index)
+ self.assertNotEqual(index, another_index)
+
+ def test_name_auto_generation(self):
+ index = GinIndex(fields=['field'])
+ index.set_name_with_model(IntegerArrayModel)
+ self.assertEqual(index.name, 'postgres_te_field_def2f8_gin')
+
+ def test_deconstruction(self):
+ index = GinIndex(fields=['title'], name='test_title_gin')
+ path, args, kwargs = index.deconstruct()
+ self.assertEqual(path, 'django.contrib.postgres.indexes.GinIndex')
+ self.assertEqual(args, ())
+ self.assertEqual(kwargs, {'fields': ['title'], 'name': 'test_title_gin'})
+
+
+class SchemaTests(PostgreSQLTestCase):
+
+ def get_indexes(self, table):
+ """
+ Get the indexes on the table using a new cursor.
+ """
+ with connection.cursor() as cursor:
+ return connection.introspection.get_indexes(cursor, table)
+
+ def test_gin_index(self):
+ # Ensure the table is there and doesn't have an index.
+ self.assertNotIn('field', self.get_indexes(IntegerArrayModel._meta.db_table))
+ # Add the index
+ index = GinIndex(fields=['field'], name='integer_array_model_field_gin')
+ with connection.schema_editor() as editor:
+ editor.add_index(IntegerArrayModel, index)
+ self.assertIn('field', self.get_indexes(IntegerArrayModel._meta.db_table))
+ self.assertEqual(self.get_indexes(IntegerArrayModel._meta.db_table)['field']['type'], 'gin')
+ # Drop the index
+ with connection.schema_editor() as editor:
+ editor.remove_index(IntegerArrayModel, index)
+ self.assertNotIn('field', self.get_indexes(IntegerArrayModel._meta.db_table))
diff --git a/tests/schema/tests.py b/tests/schema/tests.py
index 9622a443a9..5baba26e00 100644
--- a/tests/schema/tests.py
+++ b/tests/schema/tests.py
@@ -1803,6 +1803,7 @@ class SchemaTests(TransactionTestCase):
editor.sql_create_index % {
"table": editor.quote_name(table),
"name": editor.quote_name(constraint_name),
+ "using": "",
"columns": editor.quote_name(column),
"extra": "",
}