Fixed #20888 -- Added support for column order in class-based indexes.
This commit is contained in:
parent
6b842c5998
commit
311a8e8d50
|
@ -17,6 +17,11 @@ class Index(object):
|
||||||
if not fields:
|
if not fields:
|
||||||
raise ValueError('At least one field is required to define an index.')
|
raise ValueError('At least one field is required to define an index.')
|
||||||
self.fields = fields
|
self.fields = fields
|
||||||
|
# A list of 2-tuple with the field name and ordering ('' or 'DESC').
|
||||||
|
self.fields_orders = [
|
||||||
|
(field_name[1:], 'DESC') if field_name.startswith('-') else (field_name, '')
|
||||||
|
for field_name in self.fields
|
||||||
|
]
|
||||||
self.name = name or ''
|
self.name = name or ''
|
||||||
if self.name:
|
if self.name:
|
||||||
errors = self.check_name()
|
errors = self.check_name()
|
||||||
|
@ -38,15 +43,17 @@ class Index(object):
|
||||||
return errors
|
return errors
|
||||||
|
|
||||||
def create_sql(self, model, schema_editor):
|
def create_sql(self, model, schema_editor):
|
||||||
fields = [model._meta.get_field(field) for field in self.fields]
|
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)
|
tablespace_sql = schema_editor._get_index_tablespace_sql(model, fields)
|
||||||
columns = [field.column for field in fields]
|
|
||||||
|
|
||||||
quote_name = schema_editor.quote_name
|
quote_name = schema_editor.quote_name
|
||||||
|
columns = [
|
||||||
|
('%s %s' % (quote_name(field.column), order)).strip()
|
||||||
|
for field, (field_name, order) in zip(fields, self.fields_orders)
|
||||||
|
]
|
||||||
return schema_editor.sql_create_index % {
|
return schema_editor.sql_create_index % {
|
||||||
'table': quote_name(model._meta.db_table),
|
'table': quote_name(model._meta.db_table),
|
||||||
'name': quote_name(self.name),
|
'name': quote_name(self.name),
|
||||||
'columns': ', '.join(quote_name(column) for column in columns),
|
'columns': ', '.join(columns),
|
||||||
'extra': tablespace_sql,
|
'extra': tablespace_sql,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,8 +89,12 @@ class Index(object):
|
||||||
fit its size by truncating the excess length.
|
fit its size by truncating the excess length.
|
||||||
"""
|
"""
|
||||||
table_name = model._meta.db_table
|
table_name = model._meta.db_table
|
||||||
column_names = [model._meta.get_field(field).column for field in self.fields]
|
column_names = [model._meta.get_field(field_name).column for field_name, order in self.fields_orders]
|
||||||
hash_data = [table_name] + column_names + [self.suffix]
|
column_names_with_order = [
|
||||||
|
(('-%s' if order else '%s') % column_name)
|
||||||
|
for column_name, (field_name, order) in zip(column_names, self.fields_orders)
|
||||||
|
]
|
||||||
|
hash_data = [table_name] + column_names_with_order + [self.suffix]
|
||||||
self.name = '%s_%s_%s' % (
|
self.name = '%s_%s_%s' % (
|
||||||
table_name[:11],
|
table_name[:11],
|
||||||
column_names[0][:7],
|
column_names[0][:7],
|
||||||
|
|
|
@ -34,6 +34,20 @@ options`_.
|
||||||
|
|
||||||
A list of the name of the fields on which the index is desired.
|
A list of the name of the fields on which the index is desired.
|
||||||
|
|
||||||
|
By default, indexes are created with an ascending order for each column. To
|
||||||
|
define an index with a descending order for a column, add a hyphen before the
|
||||||
|
field's name.
|
||||||
|
|
||||||
|
For example ``Index(fields=['headline', '-pub_date'])`` would create SQL with
|
||||||
|
``(headline, pub_date DESC)``. Index ordering isn't supported on MySQL. In that
|
||||||
|
case, a descending index is created as a normal index.
|
||||||
|
|
||||||
|
.. admonition:: Support for column ordering on SQLite
|
||||||
|
|
||||||
|
Column ordering is supported on SQLite 3.3.0+ and only for some database
|
||||||
|
file formats. Refer to the `SQLite docs
|
||||||
|
<https://www.sqlite.org/lang_createindex.html>`_ for specifics.
|
||||||
|
|
||||||
``name``
|
``name``
|
||||||
--------
|
--------
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,11 @@ class IndexesTests(TestCase):
|
||||||
index.set_name_with_model(Book)
|
index.set_name_with_model(Book)
|
||||||
self.assertEqual(index.name, 'model_index_author_0f5565_idx')
|
self.assertEqual(index.name, 'model_index_author_0f5565_idx')
|
||||||
|
|
||||||
|
# '-' for DESC columns should be accounted for in the index name.
|
||||||
|
index = models.Index(fields=['-author'])
|
||||||
|
index.set_name_with_model(Book)
|
||||||
|
self.assertEqual(index.name, 'model_index_author_708765_idx')
|
||||||
|
|
||||||
# fields may be truncated in the name. db_column is used for naming.
|
# fields may be truncated in the name. db_column is used for naming.
|
||||||
long_field_index = models.Index(fields=['pages'])
|
long_field_index = models.Index(fields=['pages'])
|
||||||
long_field_index.set_name_with_model(Book)
|
long_field_index.set_name_with_model(Book)
|
||||||
|
|
|
@ -156,6 +156,12 @@ class SchemaTests(TransactionTestCase):
|
||||||
counts['indexes'] += 1
|
counts['indexes'] += 1
|
||||||
return counts
|
return counts
|
||||||
|
|
||||||
|
def assertIndexOrder(self, table, index, order):
|
||||||
|
constraints = self.get_constraints(table)
|
||||||
|
self.assertIn(index, constraints)
|
||||||
|
index_orders = constraints[index]['orders']
|
||||||
|
self.assertTrue(all([(val == expected) for val, expected in zip(index_orders, order)]))
|
||||||
|
|
||||||
# Tests
|
# Tests
|
||||||
def test_creation_deletion(self):
|
def test_creation_deletion(self):
|
||||||
"""
|
"""
|
||||||
|
@ -1597,6 +1603,24 @@ class SchemaTests(TransactionTestCase):
|
||||||
editor.remove_index(Author, index)
|
editor.remove_index(Author, index)
|
||||||
self.assertNotIn('name', self.get_indexes(Author._meta.db_table))
|
self.assertNotIn('name', self.get_indexes(Author._meta.db_table))
|
||||||
|
|
||||||
|
def test_order_index(self):
|
||||||
|
"""
|
||||||
|
Indexes defined with ordering (ASC/DESC) defined on column
|
||||||
|
"""
|
||||||
|
with connection.schema_editor() as editor:
|
||||||
|
editor.create_model(Author)
|
||||||
|
# The table doesn't have an index
|
||||||
|
self.assertNotIn('title', self.get_indexes(Author._meta.db_table))
|
||||||
|
index_name = 'author_name_idx'
|
||||||
|
# Add the index
|
||||||
|
index = Index(fields=['name', '-weight'], name=index_name)
|
||||||
|
with connection.schema_editor() as editor:
|
||||||
|
editor.add_index(Author, index)
|
||||||
|
if connection.features.supports_index_column_ordering:
|
||||||
|
if connection.features.uppercases_column_names:
|
||||||
|
index_name = index_name.upper()
|
||||||
|
self.assertIndexOrder(Author._meta.db_table, index_name, ['ASC', 'DESC'])
|
||||||
|
|
||||||
def test_indexes(self):
|
def test_indexes(self):
|
||||||
"""
|
"""
|
||||||
Tests creation/altering of indexes
|
Tests creation/altering of indexes
|
||||||
|
|
Loading…
Reference in New Issue