Fixed #26034 -- Fixed incorrect index handling on PostgreSQL on Char/TextField with unique=True and db_index=True.

Thanks Simon Charette for review.
This commit is contained in:
Tim Graham 2016-01-07 20:06:58 -05:00
parent 54d3ba8406
commit 56aaae58a7
4 changed files with 72 additions and 2 deletions

View File

@ -111,13 +111,13 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
new_db_params, strict, new_db_params, strict,
) )
# Added an index? Create any PostgreSQL-specific indexes. # Added an index? Create any PostgreSQL-specific indexes.
if ((not old_field.db_index and new_field.db_index) or (not old_field.unique and new_field.unique)): if not old_field.db_index and not old_field.unique and (new_field.db_index or new_field.unique):
like_index_statement = self._create_like_index_sql(model, new_field) like_index_statement = self._create_like_index_sql(model, new_field)
if like_index_statement is not None: if like_index_statement is not None:
self.execute(like_index_statement) self.execute(like_index_statement)
# Removed an index? Drop any PostgreSQL-specific indexes. # Removed an index? Drop any PostgreSQL-specific indexes.
if ((not new_field.db_index and old_field.db_index) or (not new_field.unique and old_field.unique)): if (old_field.db_index or old_field.unique) and not (new_field.db_index or new_field.unique):
index_to_remove = self._create_index_name(model, [old_field.column], suffix='_like') index_to_remove = self._create_index_name(model, [old_field.column], suffix='_like')
index_names = self._constraint_names(model, [old_field.column], index=True) index_names = self._constraint_names(model, [old_field.column], index=True)
for index_name in index_names: for index_name in index_names:

View File

@ -18,3 +18,8 @@ Bugfixes
* Fixed a regression that caused the incorrect day to be selected when opening * Fixed a regression that caused the incorrect day to be selected when opening
the admin calendar widget for timezones from GMT+0100 to GMT+1200 the admin calendar widget for timezones from GMT+0100 to GMT+1200
(:ticket:`24980`). (:ticket:`24980`).
* Fixed incorrect index handling in migrations on PostgreSQL when adding
``db_index=True`` or ``unique=True`` to a ``CharField`` or ``TextField`` that
already had the other specified, or when removing one of them from a field
that had both (:ticket:`26034`).

View File

@ -25,3 +25,8 @@ Bugfixes
* Fixed a regression in the admin's edit related model popup that caused an * Fixed a regression in the admin's edit related model popup that caused an
escaped value to be displayed in the select dropdown of the parent window escaped value to be displayed in the select dropdown of the parent window
(:ticket:`25997`). (:ticket:`25997`).
* Fixed incorrect index handling in migrations on PostgreSQL when adding
``db_index=True`` or ``unique=True`` to a ``CharField`` or ``TextField`` that
already had the other specified, or when removing one of them from a field
that had both (:ticket:`26034`).

View File

@ -1757,3 +1757,63 @@ class SchemaTests(TransactionTestCase):
with connection.schema_editor() as editor: with connection.schema_editor() as editor:
editor.alter_field(Note, new_field, old_field, strict=True) editor.alter_field(Note, new_field, old_field, strict=True)
self.assertEqual(self.get_constraints_for_column(Note, 'info'), []) self.assertEqual(self.get_constraints_for_column(Note, 'info'), [])
@unittest.skipUnless(connection.vendor == 'postgresql', "PostgreSQL specific")
def test_alter_field_add_unique_to_charfield_with_db_index(self):
# Create the table and verify initial indexes.
with connection.schema_editor() as editor:
editor.create_model(BookWithoutAuthor)
self.assertEqual(
self.get_constraints_for_column(BookWithoutAuthor, 'title'),
['schema_book_d5d3db17', 'schema_book_title_2dfb2dff_like']
)
# Alter to add unique=True (should add 1 index)
old_field = BookWithoutAuthor._meta.get_field('title')
new_field = CharField(max_length=100, db_index=True, unique=True)
new_field.set_attributes_from_name('title')
with connection.schema_editor() as editor:
editor.alter_field(BookWithoutAuthor, old_field, new_field, strict=True)
self.assertEqual(
self.get_constraints_for_column(BookWithoutAuthor, 'title'),
['schema_book_d5d3db17', 'schema_book_title_2dfb2dff_like', 'schema_book_title_2dfb2dff_uniq']
)
# Alter to remove unique=True (should drop unique index) # XXX: bug!
old_field = BookWithoutAuthor._meta.get_field('title')
new_field = CharField(max_length=100, db_index=True)
new_field.set_attributes_from_name('title')
with connection.schema_editor() as editor:
editor.alter_field(BookWithoutAuthor, old_field, new_field, strict=True)
self.assertEqual(
self.get_constraints_for_column(BookWithoutAuthor, 'title'),
['schema_book_d5d3db17', 'schema_book_title_2dfb2dff_like', 'schema_book_title_2dfb2dff_uniq']
)
@unittest.skipUnless(connection.vendor == 'postgresql', "PostgreSQL specific")
def test_alter_field_add_db_index_to_charfield_with_unique(self):
# Create the table and verify initial indexes.
with connection.schema_editor() as editor:
editor.create_model(Tag)
self.assertEqual(
self.get_constraints_for_column(Tag, 'slug'),
['schema_tag_slug_2c418ba3_like', 'schema_tag_slug_key']
)
# Alter to add db_index=True
old_field = Tag._meta.get_field('slug')
new_field = SlugField(db_index=True, unique=True)
new_field.set_attributes_from_name('slug')
with connection.schema_editor() as editor:
editor.alter_field(Tag, old_field, new_field, strict=True)
self.assertEqual(
self.get_constraints_for_column(Tag, 'slug'),
['schema_tag_slug_2c418ba3_like', 'schema_tag_slug_key']
)
# Alter to remove db_index=True
old_field = Tag._meta.get_field('slug')
new_field = SlugField(unique=True)
new_field.set_attributes_from_name('slug')
with connection.schema_editor() as editor:
editor.alter_field(Tag, old_field, new_field, strict=True)
self.assertEqual(
self.get_constraints_for_column(Tag, 'slug'),
['schema_tag_slug_2c418ba3_like', 'schema_tag_slug_key']
)