mirror of
https://github.com/django/django.git
synced 2025-10-24 06:06:09 +00:00
Refs #30172 -- Prevented removing a field's check or unique constraint from removing Meta constraints.
This commit is contained in:
committed by
Tim Graham
parent
218a485bf1
commit
4bb859e246
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user