mirror of
https://github.com/django/django.git
synced 2025-07-12 07:45:11 +00:00
Fixed #30916 -- Added support for functional unique constraints.
Thanks Ian Foote and Mariusz Felisiak for reviews.
This commit is contained in:
parent
19ce1d493a
commit
3aa545281e
15 changed files with 779 additions and 38 deletions
|
@ -1,6 +1,7 @@
|
|||
import datetime
|
||||
from unittest import mock
|
||||
|
||||
from django.contrib.postgres.indexes import OpClass
|
||||
from django.db import (
|
||||
IntegrityError, NotSupportedError, connection, transaction,
|
||||
)
|
||||
|
@ -8,8 +9,8 @@ from django.db.models import (
|
|||
CheckConstraint, Deferrable, F, Func, IntegerField, Q, UniqueConstraint,
|
||||
)
|
||||
from django.db.models.fields.json import KeyTextTransform
|
||||
from django.db.models.functions import Cast, Left
|
||||
from django.test import skipUnlessDBFeature
|
||||
from django.db.models.functions import Cast, Left, Lower
|
||||
from django.test import modify_settings, skipUnlessDBFeature
|
||||
from django.utils import timezone
|
||||
|
||||
from . import PostgreSQLTestCase
|
||||
|
@ -26,6 +27,7 @@ except ImportError:
|
|||
pass
|
||||
|
||||
|
||||
@modify_settings(INSTALLED_APPS={'append': 'django.contrib.postgres'})
|
||||
class SchemaTests(PostgreSQLTestCase):
|
||||
get_opclass_query = '''
|
||||
SELECT opcname, c.relname FROM pg_opclass AS oc
|
||||
|
@ -166,6 +168,33 @@ class SchemaTests(PostgreSQLTestCase):
|
|||
[('varchar_pattern_ops', constraint.name)],
|
||||
)
|
||||
|
||||
@skipUnlessDBFeature('supports_expression_indexes')
|
||||
def test_opclass_func(self):
|
||||
constraint = UniqueConstraint(
|
||||
OpClass(Lower('scene'), name='text_pattern_ops'),
|
||||
name='test_opclass_func',
|
||||
)
|
||||
with connection.schema_editor() as editor:
|
||||
editor.add_constraint(Scene, constraint)
|
||||
constraints = self.get_constraints(Scene._meta.db_table)
|
||||
self.assertIs(constraints[constraint.name]['unique'], True)
|
||||
self.assertIn(constraint.name, constraints)
|
||||
with editor.connection.cursor() as cursor:
|
||||
cursor.execute(self.get_opclass_query, [constraint.name])
|
||||
self.assertEqual(
|
||||
cursor.fetchall(),
|
||||
[('text_pattern_ops', constraint.name)],
|
||||
)
|
||||
Scene.objects.create(scene='Scene 10', setting='The dark forest of Ewing')
|
||||
with self.assertRaises(IntegrityError), transaction.atomic():
|
||||
Scene.objects.create(scene='ScEnE 10', setting="Sir Bedemir's Castle")
|
||||
Scene.objects.create(scene='Scene 5', setting="Sir Bedemir's Castle")
|
||||
# Drop the constraint.
|
||||
with connection.schema_editor() as editor:
|
||||
editor.remove_constraint(Scene, constraint)
|
||||
self.assertNotIn(constraint.name, self.get_constraints(Scene._meta.db_table))
|
||||
Scene.objects.create(scene='ScEnE 10', setting="Sir Bedemir's Castle")
|
||||
|
||||
|
||||
class ExclusionConstraintTests(PostgreSQLTestCase):
|
||||
def get_constraints(self, table):
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue