From fa5f3291e7f2611d53e64ab481ebe951b0161791 Mon Sep 17 00:00:00 2001 From: Hannes Ljungberg Date: Wed, 23 Oct 2019 22:16:55 +0200 Subject: [PATCH] Fixed #30903 -- Fixed migrations crash on PostgreSQL when adding Index with opclasses and ordering. --- AUTHORS | 1 + django/db/backends/ddl_references.py | 11 ++++++----- docs/releases/2.2.7.txt | 4 ++++ tests/indexes/tests.py | 27 +++++++++++++++++++++++++++ 4 files changed, 38 insertions(+), 5 deletions(-) diff --git a/AUTHORS b/AUTHORS index 06998e7c3c..8e126b2537 100644 --- a/AUTHORS +++ b/AUTHORS @@ -340,6 +340,7 @@ answer newbie questions, and generally made Django that much better: Gustavo Picon hambaloney Hang Park + Hannes Ljungberg Hannes Struß Hasan Ramezani Hawkeye diff --git a/django/db/backends/ddl_references.py b/django/db/backends/ddl_references.py index d71f6169ea..44e49806f8 100644 --- a/django/db/backends/ddl_references.py +++ b/django/db/backends/ddl_references.py @@ -110,13 +110,14 @@ class IndexColumns(Columns): def __str__(self): def col_str(column, idx): - try: - col = self.quote_name(column) + self.col_suffixes[idx] - except IndexError: - col = self.quote_name(column) # Index.__init__() guarantees that self.opclasses is the same # length as self.columns. - return '{} {}'.format(col, self.opclasses[idx]) + col = '{} {}'.format(self.quote_name(column), self.opclasses[idx]) + try: + col = '{} {}'.format(col, self.col_suffixes[idx]) + except IndexError: + pass + return col return ', '.join(col_str(column, idx) for idx, column in enumerate(self.columns)) diff --git a/docs/releases/2.2.7.txt b/docs/releases/2.2.7.txt index 3232b5c5e8..cf1f52a685 100644 --- a/docs/releases/2.2.7.txt +++ b/docs/releases/2.2.7.txt @@ -17,3 +17,7 @@ Bugfixes * Prevented :option:`migrate --plan` from showing that ``RunPython`` operations are irreversible when ``reverse_code`` callables don't have docstrings or when showing a forward migration plan (:ticket:`30870`). + +* Fixed migrations crash on PostgreSQL when adding an + :class:`~django.db.models.Index` with fields ordering and + :attr:`~.Index.opclasses` (:ticket:`30903`). diff --git a/tests/indexes/tests.py b/tests/indexes/tests.py index 2272cadc4f..588feaddff 100644 --- a/tests/indexes/tests.py +++ b/tests/indexes/tests.py @@ -196,6 +196,33 @@ class SchemaIndexesPostgreSQLTests(TransactionTestCase): cursor.execute(self.get_opclass_query % indexname) self.assertCountEqual(cursor.fetchall(), [('text_pattern_ops', indexname)]) + def test_ops_class_descending(self): + indexname = 'test_ops_class_ordered' + index = Index( + name=indexname, + fields=['-body'], + opclasses=['text_pattern_ops'], + ) + with connection.schema_editor() as editor: + editor.add_index(IndexedArticle2, index) + with editor.connection.cursor() as cursor: + cursor.execute(self.get_opclass_query % indexname) + self.assertCountEqual(cursor.fetchall(), [('text_pattern_ops', indexname)]) + + def test_ops_class_descending_partial(self): + indexname = 'test_ops_class_ordered_partial' + index = Index( + name=indexname, + fields=['-body'], + opclasses=['text_pattern_ops'], + condition=Q(headline__contains='China'), + ) + with connection.schema_editor() as editor: + editor.add_index(IndexedArticle2, index) + with editor.connection.cursor() as cursor: + cursor.execute(self.get_opclass_query % indexname) + self.assertCountEqual(cursor.fetchall(), [('text_pattern_ops', indexname)]) + @skipUnless(connection.vendor == 'mysql', 'MySQL tests') class SchemaIndexesMySQLTests(TransactionTestCase):