diff options
| author | Paveł Tyślacki <pavel.tyslacki@gmail.com> | 2019-02-11 17:17:06 +0300 |
|---|---|---|
| committer | Tim Graham <timograham@gmail.com> | 2019-03-17 20:50:22 -0400 |
| commit | 4bb859e24694f6cb8974ed9d2225f18214338ea3 (patch) | |
| tree | aa3057496526650c6b0f460a29cf7f93105b1f92 /tests/schema | |
| parent | 218a485bf13aa92d49c5da72c66053c18268fc14 (diff) | |
Refs #30172 -- Prevented removing a field's check or unique constraint from removing Meta constraints.
Diffstat (limited to 'tests/schema')
| -rw-r--r-- | tests/schema/models.py | 7 | ||||
| -rw-r--r-- | tests/schema/tests.py | 104 |
2 files changed, 107 insertions, 4 deletions
diff --git a/tests/schema/models.py b/tests/schema/models.py index f6bdbd8815..2c277c681b 100644 --- a/tests/schema/models.py +++ b/tests/schema/models.py @@ -55,6 +55,13 @@ class AuthorWithIndexedName(models.Model): apps = new_apps +class AuthorWithUniqueName(models.Model): + name = models.CharField(max_length=255, unique=True) + + class Meta: + apps = new_apps + + class Book(models.Model): author = models.ForeignKey(Author, models.CASCADE) title = models.CharField(max_length=100, db_index=True) diff --git a/tests/schema/tests.py b/tests/schema/tests.py index 00ce2e494e..050e4c9385 100644 --- a/tests/schema/tests.py +++ b/tests/schema/tests.py @@ -7,7 +7,8 @@ from unittest import mock from django.db import ( DatabaseError, IntegrityError, OperationalError, connection, ) -from django.db.models import Model +from django.db.models import Model, Q +from django.db.models.constraints import CheckConstraint, UniqueConstraint from django.db.models.deletion import CASCADE, PROTECT from django.db.models.fields import ( AutoField, BigAutoField, BigIntegerField, BinaryField, BooleanField, @@ -31,9 +32,10 @@ from .fields import ( from .models import ( 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, + AuthorWithUniqueName, Book, BookForeignObj, BookWeak, BookWithLongName, + BookWithO2O, BookWithoutAuthor, BookWithSlug, IntegerPK, Node, Note, + NoteRename, Tag, TagIndexed, TagM2MTest, TagUniqueRename, Thing, + UniqueTest, new_apps, ) @@ -1545,6 +1547,53 @@ class SchemaTests(TransactionTestCase): if not any(details['columns'] == ['height'] and details['check'] for details in constraints.values()): self.fail("No check constraint for height found") + @skipUnlessDBFeature('supports_column_check_constraints') + def test_remove_field_check_does_not_remove_meta_constraints(self): + with connection.schema_editor() as editor: + editor.create_model(Author) + # Add the custom check constraint + constraint = CheckConstraint(check=Q(height__gte=0), name='author_height_gte_0_check') + custom_constraint_name = constraint.name + Author._meta.constraints = [constraint] + with connection.schema_editor() as editor: + editor.add_constraint(Author, constraint) + # Ensure the constraints exist + constraints = self.get_constraints(Author._meta.db_table) + self.assertIn(custom_constraint_name, constraints) + other_constraints = [ + name for name, details in constraints.items() + if details['columns'] == ['height'] and details['check'] and name != custom_constraint_name + ] + self.assertEqual(len(other_constraints), 1) + # Alter the column to remove field check + old_field = Author._meta.get_field('height') + new_field = IntegerField(null=True, blank=True) + new_field.set_attributes_from_name('height') + with connection.schema_editor() as editor: + editor.alter_field(Author, old_field, new_field, strict=True) + constraints = self.get_constraints(Author._meta.db_table) + self.assertIn(custom_constraint_name, constraints) + other_constraints = [ + name for name, details in constraints.items() + if details['columns'] == ['height'] and details['check'] and name != custom_constraint_name + ] + self.assertEqual(len(other_constraints), 0) + # Alter the column to re-add field check + new_field2 = Author._meta.get_field('height') + with connection.schema_editor() as editor: + editor.alter_field(Author, new_field, new_field2, strict=True) + constraints = self.get_constraints(Author._meta.db_table) + self.assertIn(custom_constraint_name, constraints) + other_constraints = [ + name for name, details in constraints.items() + if details['columns'] == ['height'] and details['check'] and name != custom_constraint_name + ] + self.assertEqual(len(other_constraints), 1) + # Drop the check constraint + with connection.schema_editor() as editor: + Author._meta.constraints = [] + editor.remove_constraint(Author, constraint) + def test_unique(self): """ Tests removing and adding unique constraints to a single column. @@ -1671,6 +1720,53 @@ class SchemaTests(TransactionTestCase): with self.assertRaises(IntegrityError): Tag.objects.create(title='bar', slug='foo') + @skipUnlessDBFeature('allows_multiple_constraints_on_same_fields') + def test_remove_field_unique_does_not_remove_meta_constraints(self): + with connection.schema_editor() as editor: + editor.create_model(AuthorWithUniqueName) + # Add the custom unique constraint + constraint = UniqueConstraint(fields=['name'], name='author_name_uniq') + custom_constraint_name = constraint.name + AuthorWithUniqueName._meta.constraints = [constraint] + with connection.schema_editor() as editor: + editor.add_constraint(AuthorWithUniqueName, constraint) + # Ensure the constraints exist + constraints = self.get_constraints(AuthorWithUniqueName._meta.db_table) + self.assertIn(custom_constraint_name, constraints) + other_constraints = [ + name for name, details in constraints.items() + if details['columns'] == ['name'] and details['unique'] and name != custom_constraint_name + ] + self.assertEqual(len(other_constraints), 1) + # Alter the column to remove field uniqueness + old_field = AuthorWithUniqueName._meta.get_field('name') + new_field = CharField(max_length=255) + new_field.set_attributes_from_name('name') + with connection.schema_editor() as editor: + editor.alter_field(AuthorWithUniqueName, old_field, new_field, strict=True) + constraints = self.get_constraints(AuthorWithUniqueName._meta.db_table) + self.assertIn(custom_constraint_name, constraints) + other_constraints = [ + name for name, details in constraints.items() + if details['columns'] == ['name'] and details['unique'] and name != custom_constraint_name + ] + self.assertEqual(len(other_constraints), 0) + # Alter the column to re-add field uniqueness + new_field2 = AuthorWithUniqueName._meta.get_field('name') + with connection.schema_editor() as editor: + editor.alter_field(AuthorWithUniqueName, new_field, new_field2, strict=True) + constraints = self.get_constraints(AuthorWithUniqueName._meta.db_table) + self.assertIn(custom_constraint_name, constraints) + other_constraints = [ + name for name, details in constraints.items() + if details['columns'] == ['name'] and details['unique'] and name != custom_constraint_name + ] + self.assertEqual(len(other_constraints), 1) + # Drop the unique constraint + with connection.schema_editor() as editor: + AuthorWithUniqueName._meta.constraints = [] + editor.remove_constraint(AuthorWithUniqueName, constraint) + def test_unique_together(self): """ Tests removing and adding unique_together constraints on a model. |
