@@ -227,6 +227,18 @@ def get_constraints_for_column(self, model, column_name):
227
227
constraints_for_column .append (name )
228
228
return sorted (constraints_for_column )
229
229
230
+ def get_constraint_opclasses (self , constraint_name ):
231
+ with connection .cursor () as cursor :
232
+ sql = """
233
+ SELECT opcname
234
+ FROM pg_opclass AS oc
235
+ JOIN pg_index as i on oc.oid = ANY(i.indclass)
236
+ JOIN pg_class as c on c.oid = i.indexrelid
237
+ WHERE c.relname = %s
238
+ """
239
+ cursor .execute (sql , [constraint_name ])
240
+ return [row [0 ] for row in cursor .fetchall ()]
241
+
230
242
def check_added_field_default (
231
243
self ,
232
244
schema_editor ,
@@ -1378,6 +1390,95 @@ class Meta:
1378
1390
)
1379
1391
self .assertIn ("field" , self .get_uniques (CiCharModel ._meta .db_table ))
1380
1392
1393
+ @isolate_apps ("schema" )
1394
+ @unittest .skipUnless (connection .vendor == "postgresql" , "PostgreSQL specific" )
1395
+ @skipUnlessDBFeature ("supports_collation_on_charfield" )
1396
+ def test_unique_with_deterministic_collation_charfield (self ):
1397
+ deterministic_collation = connection .features .test_collations .get (
1398
+ "deterministic"
1399
+ )
1400
+ if not deterministic_collation :
1401
+ self .skipTest ("This backend does not support deterministic collations." )
1402
+
1403
+ class CharModel (Model ):
1404
+ field = CharField (db_collation = deterministic_collation , unique = True )
1405
+
1406
+ class Meta :
1407
+ app_label = "schema"
1408
+
1409
+ # Create the table.
1410
+ with connection .schema_editor () as editor :
1411
+ editor .create_model (CharModel )
1412
+ self .isolated_local_models = [CharModel ]
1413
+ constraints = self .get_constraints_for_column (
1414
+ CharModel , CharModel ._meta .get_field ("field" ).column
1415
+ )
1416
+ self .assertIn ("schema_charmodel_field_8b338dea_like" , constraints )
1417
+ self .assertIn (
1418
+ "varchar_pattern_ops" ,
1419
+ self .get_constraint_opclasses ("schema_charmodel_field_8b338dea_like" ),
1420
+ )
1421
+ self .assertEqual (
1422
+ self .get_column_collation (CharModel ._meta .db_table , "field" ),
1423
+ deterministic_collation ,
1424
+ )
1425
+ self .assertIn ("field" , self .get_uniques (CharModel ._meta .db_table ))
1426
+
1427
+ @isolate_apps ("schema" )
1428
+ @unittest .skipUnless (connection .vendor == "postgresql" , "PostgreSQL specific" )
1429
+ @skipUnlessDBFeature ("supports_collation_on_charfield" )
1430
+ def test_relation_to_deterministic_collation_charfield (self ):
1431
+ deterministic_collation = connection .features .test_collations .get (
1432
+ "deterministic"
1433
+ )
1434
+ if not deterministic_collation :
1435
+ self .skipTest ("This backend does not support deterministic collations." )
1436
+
1437
+ class CharModel (Model ):
1438
+ field = CharField (db_collation = deterministic_collation , unique = True )
1439
+
1440
+ class Meta :
1441
+ app_label = "schema"
1442
+
1443
+ class RelationModel (Model ):
1444
+ field = OneToOneField (CharModel , CASCADE , to_field = "field" )
1445
+
1446
+ class Meta :
1447
+ app_label = "schema"
1448
+
1449
+ # Create the table.
1450
+ with connection .schema_editor () as editor :
1451
+ editor .create_model (CharModel )
1452
+ editor .create_model (RelationModel )
1453
+ self .isolated_local_models = [CharModel , RelationModel ]
1454
+ constraints = self .get_constraints_for_column (
1455
+ CharModel , CharModel ._meta .get_field ("field" ).column
1456
+ )
1457
+ self .assertIn ("schema_charmodel_field_8b338dea_like" , constraints )
1458
+ self .assertIn (
1459
+ "varchar_pattern_ops" ,
1460
+ self .get_constraint_opclasses ("schema_charmodel_field_8b338dea_like" ),
1461
+ )
1462
+ rel_constraints = self .get_constraints_for_column (
1463
+ RelationModel , RelationModel ._meta .get_field ("field" ).column
1464
+ )
1465
+ self .assertIn ("schema_relationmodel_field_id_395fbb08_like" , rel_constraints )
1466
+ self .assertIn (
1467
+ "varchar_pattern_ops" ,
1468
+ self .get_constraint_opclasses (
1469
+ "schema_relationmodel_field_id_395fbb08_like"
1470
+ ),
1471
+ )
1472
+ self .assertEqual (
1473
+ self .get_column_collation (RelationModel ._meta .db_table , "field_id" ),
1474
+ deterministic_collation ,
1475
+ )
1476
+ self .assertEqual (
1477
+ self .get_column_collation (CharModel ._meta .db_table , "field" ),
1478
+ deterministic_collation ,
1479
+ )
1480
+ self .assertIn ("field_id" , self .get_uniques (RelationModel ._meta .db_table ))
1481
+
1381
1482
def test_alter_textfield_to_null (self ):
1382
1483
"""
1383
1484
#24307 - Should skip an alter statement on databases with
0 commit comments