Fixed #27860 -- Dropped varchar_pattern_ops/text_pattern_ops index before altering char/text field in PostgreSQL.
Thanks Tim Graham for the review.
This commit is contained in:
parent
538bf43458
commit
91b2bc3e70
|
@ -104,6 +104,15 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
|
||||||
|
|
||||||
def _alter_field(self, model, old_field, new_field, old_type, new_type,
|
def _alter_field(self, model, old_field, new_field, old_type, new_type,
|
||||||
old_db_params, new_db_params, strict=False):
|
old_db_params, new_db_params, strict=False):
|
||||||
|
# Drop indexes on varchar/text columns that are changing to a different
|
||||||
|
# type.
|
||||||
|
if (old_field.db_index or old_field.unique) and (
|
||||||
|
(old_type.startswith('varchar') and not new_type.startswith('varchar')) or
|
||||||
|
(old_type.startswith('text') and not new_type.startswith('text'))
|
||||||
|
):
|
||||||
|
index_name = self._create_index_name(model, [old_field.column], suffix='_like')
|
||||||
|
self.execute(self._delete_constraint_sql(self.sql_delete_index, model, index_name))
|
||||||
|
|
||||||
super()._alter_field(
|
super()._alter_field(
|
||||||
model, old_field, new_field, old_type, new_type, old_db_params,
|
model, old_field, new_field, old_type, new_type, old_db_params,
|
||||||
new_db_params, strict,
|
new_db_params, strict,
|
||||||
|
|
|
@ -17,6 +17,13 @@ class Author(models.Model):
|
||||||
apps = new_apps
|
apps = new_apps
|
||||||
|
|
||||||
|
|
||||||
|
class AuthorCharFieldWithIndex(models.Model):
|
||||||
|
char_field = models.CharField(max_length=31, db_index=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
apps = new_apps
|
||||||
|
|
||||||
|
|
||||||
class AuthorTextFieldWithIndex(models.Model):
|
class AuthorTextFieldWithIndex(models.Model):
|
||||||
text_field = models.TextField(db_index=True)
|
text_field = models.TextField(db_index=True)
|
||||||
|
|
||||||
|
|
|
@ -29,11 +29,11 @@ from .fields import (
|
||||||
CustomManyToManyField, InheritedManyToManyField, MediumBlobField,
|
CustomManyToManyField, InheritedManyToManyField, MediumBlobField,
|
||||||
)
|
)
|
||||||
from .models import (
|
from .models import (
|
||||||
Author, AuthorTextFieldWithIndex, AuthorWithDefaultHeight,
|
Author, AuthorCharFieldWithIndex, AuthorTextFieldWithIndex,
|
||||||
AuthorWithEvenLongerName, AuthorWithIndexedName, Book, BookForeignObj,
|
AuthorWithDefaultHeight, AuthorWithEvenLongerName, AuthorWithIndexedName,
|
||||||
BookWeak, BookWithLongName, BookWithO2O, BookWithoutAuthor, BookWithSlug,
|
Book, BookForeignObj, BookWeak, BookWithLongName, BookWithO2O,
|
||||||
IntegerPK, Node, Note, NoteRename, Tag, TagIndexed, TagM2MTest,
|
BookWithoutAuthor, BookWithSlug, IntegerPK, Node, Note, NoteRename, Tag,
|
||||||
TagUniqueRename, Thing, UniqueTest, new_apps,
|
TagIndexed, TagM2MTest, TagUniqueRename, Thing, UniqueTest, new_apps,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -49,9 +49,10 @@ class SchemaTests(TransactionTestCase):
|
||||||
available_apps = []
|
available_apps = []
|
||||||
|
|
||||||
models = [
|
models = [
|
||||||
Author, AuthorWithDefaultHeight, AuthorWithEvenLongerName, Book,
|
Author, AuthorCharFieldWithIndex, AuthorTextFieldWithIndex,
|
||||||
BookWeak, BookWithLongName, BookWithO2O, BookWithSlug, IntegerPK, Node,
|
AuthorWithDefaultHeight, AuthorWithEvenLongerName, Book, BookWeak,
|
||||||
Note, Tag, TagIndexed, TagM2MTest, TagUniqueRename, Thing, UniqueTest,
|
BookWithLongName, BookWithO2O, BookWithSlug, IntegerPK, Node, Note,
|
||||||
|
Tag, TagIndexed, TagM2MTest, TagUniqueRename, Thing, UniqueTest,
|
||||||
]
|
]
|
||||||
|
|
||||||
# Utility functions
|
# Utility functions
|
||||||
|
@ -222,6 +223,49 @@ class SchemaTests(TransactionTestCase):
|
||||||
else:
|
else:
|
||||||
self.fail("No FK constraint for author_id found")
|
self.fail("No FK constraint for author_id found")
|
||||||
|
|
||||||
|
@skipUnlessDBFeature('supports_foreign_keys')
|
||||||
|
def test_char_field_with_db_index_to_fk(self):
|
||||||
|
# Create the table
|
||||||
|
with connection.schema_editor() as editor:
|
||||||
|
editor.create_model(Author)
|
||||||
|
editor.create_model(AuthorCharFieldWithIndex)
|
||||||
|
# Change CharField to FK
|
||||||
|
old_field = AuthorCharFieldWithIndex._meta.get_field('char_field')
|
||||||
|
new_field = ForeignKey(Author, CASCADE, blank=True)
|
||||||
|
new_field.set_attributes_from_name('char_field')
|
||||||
|
with connection.schema_editor() as editor:
|
||||||
|
editor.alter_field(AuthorCharFieldWithIndex, old_field, new_field, strict=True)
|
||||||
|
# The new FK constraint is present
|
||||||
|
constraints = self.get_constraints(AuthorCharFieldWithIndex._meta.db_table)
|
||||||
|
constraint_fk = None
|
||||||
|
for name, details in constraints.items():
|
||||||
|
if details['columns'] == ['char_field_id'] and details['foreign_key']:
|
||||||
|
constraint_fk = details['foreign_key']
|
||||||
|
break
|
||||||
|
self.assertEqual(constraint_fk, ('schema_author', 'id'))
|
||||||
|
|
||||||
|
@skipUnlessDBFeature('supports_foreign_keys')
|
||||||
|
@skipUnlessDBFeature('supports_index_on_text_field')
|
||||||
|
def test_text_field_with_db_index_to_fk(self):
|
||||||
|
# Create the table
|
||||||
|
with connection.schema_editor() as editor:
|
||||||
|
editor.create_model(Author)
|
||||||
|
editor.create_model(AuthorTextFieldWithIndex)
|
||||||
|
# Change TextField to FK
|
||||||
|
old_field = AuthorTextFieldWithIndex._meta.get_field('text_field')
|
||||||
|
new_field = ForeignKey(Author, CASCADE, blank=True)
|
||||||
|
new_field.set_attributes_from_name('text_field')
|
||||||
|
with connection.schema_editor() as editor:
|
||||||
|
editor.alter_field(AuthorTextFieldWithIndex, old_field, new_field, strict=True)
|
||||||
|
# The new FK constraint is present
|
||||||
|
constraints = self.get_constraints(AuthorTextFieldWithIndex._meta.db_table)
|
||||||
|
constraint_fk = None
|
||||||
|
for name, details in constraints.items():
|
||||||
|
if details['columns'] == ['text_field_id'] and details['foreign_key']:
|
||||||
|
constraint_fk = details['foreign_key']
|
||||||
|
break
|
||||||
|
self.assertEqual(constraint_fk, ('schema_author', 'id'))
|
||||||
|
|
||||||
@skipUnlessDBFeature('supports_foreign_keys')
|
@skipUnlessDBFeature('supports_foreign_keys')
|
||||||
def test_fk_to_proxy(self):
|
def test_fk_to_proxy(self):
|
||||||
"Creating a FK to a proxy model creates database constraints."
|
"Creating a FK to a proxy model creates database constraints."
|
||||||
|
|
Loading…
Reference in New Issue