summaryrefslogtreecommitdiff
path: root/tests/schema
diff options
context:
space:
mode:
authorPaveł Tyślacki <pavel.tyslacki@gmail.com>2019-02-11 17:17:06 +0300
committerTim Graham <timograham@gmail.com>2019-03-17 20:50:22 -0400
commit4bb859e24694f6cb8974ed9d2225f18214338ea3 (patch)
treeaa3057496526650c6b0f460a29cf7f93105b1f92 /tests/schema
parent218a485bf13aa92d49c5da72c66053c18268fc14 (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.py7
-rw-r--r--tests/schema/tests.py104
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.