mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	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:
		| @@ -104,6 +104,15 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor): | ||||
|  | ||||
|     def _alter_field(self, model, old_field, new_field, old_type, new_type, | ||||
|                      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( | ||||
|             model, old_field, new_field, old_type, new_type, old_db_params, | ||||
|             new_db_params, strict, | ||||
|   | ||||
| @@ -17,6 +17,13 @@ class Author(models.Model): | ||||
|         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): | ||||
|     text_field = models.TextField(db_index=True) | ||||
|  | ||||
|   | ||||
| @@ -29,11 +29,11 @@ from .fields import ( | ||||
|     CustomManyToManyField, InheritedManyToManyField, MediumBlobField, | ||||
| ) | ||||
| from .models import ( | ||||
|     Author, AuthorTextFieldWithIndex, AuthorWithDefaultHeight, | ||||
|     AuthorWithEvenLongerName, AuthorWithIndexedName, Book, BookForeignObj, | ||||
|     BookWeak, BookWithLongName, BookWithO2O, BookWithoutAuthor, BookWithSlug, | ||||
|     IntegerPK, Node, Note, NoteRename, Tag, TagIndexed, TagM2MTest, | ||||
|     TagUniqueRename, Thing, UniqueTest, new_apps, | ||||
|     Author, AuthorCharFieldWithIndex, AuthorTextFieldWithIndex, | ||||
|     AuthorWithDefaultHeight, AuthorWithEvenLongerName, AuthorWithIndexedName, | ||||
|     Book, BookForeignObj, BookWeak, BookWithLongName, BookWithO2O, | ||||
|     BookWithoutAuthor, BookWithSlug, IntegerPK, Node, Note, NoteRename, Tag, | ||||
|     TagIndexed, TagM2MTest, TagUniqueRename, Thing, UniqueTest, new_apps, | ||||
| ) | ||||
|  | ||||
|  | ||||
| @@ -49,9 +49,10 @@ class SchemaTests(TransactionTestCase): | ||||
|     available_apps = [] | ||||
|  | ||||
|     models = [ | ||||
|         Author, AuthorWithDefaultHeight, AuthorWithEvenLongerName, Book, | ||||
|         BookWeak, BookWithLongName, BookWithO2O, BookWithSlug, IntegerPK, Node, | ||||
|         Note, Tag, TagIndexed, TagM2MTest, TagUniqueRename, Thing, UniqueTest, | ||||
|         Author, AuthorCharFieldWithIndex, AuthorTextFieldWithIndex, | ||||
|         AuthorWithDefaultHeight, AuthorWithEvenLongerName, Book, BookWeak, | ||||
|         BookWithLongName, BookWithO2O, BookWithSlug, IntegerPK, Node, Note, | ||||
|         Tag, TagIndexed, TagM2MTest, TagUniqueRename, Thing, UniqueTest, | ||||
|     ] | ||||
|  | ||||
|     # Utility functions | ||||
| @@ -222,6 +223,49 @@ class SchemaTests(TransactionTestCase): | ||||
|         else: | ||||
|             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') | ||||
|     def test_fk_to_proxy(self): | ||||
|         "Creating a FK to a proxy model creates database constraints." | ||||
|   | ||||
		Reference in New Issue
	
	Block a user