@@ -1373,6 +1373,17 @@ def get_extra_kwargs(self):
1373
1373
1374
1374
return extra_kwargs
1375
1375
1376
+ def get_unique_together_constraints (self , model ):
1377
+ for parent_class in [model ] + list (model ._meta .parents ):
1378
+ for unique_together in parent_class ._meta .unique_together :
1379
+ yield unique_together , model ._default_manager
1380
+ for constraint in parent_class ._meta .constraints :
1381
+ if isinstance (constraint , models .UniqueConstraint ):
1382
+ yield (
1383
+ constraint .fields ,
1384
+ model ._default_manager .filter (constraint .condition ) if constraint .condition else model ._default_manager
1385
+ )
1386
+
1376
1387
def get_uniqueness_extra_kwargs (self , field_names , declared_fields , extra_kwargs ):
1377
1388
"""
1378
1389
Return any additional field options that need to be included as a
@@ -1401,12 +1412,11 @@ def get_uniqueness_extra_kwargs(self, field_names, declared_fields, extra_kwargs
1401
1412
1402
1413
unique_constraint_names -= {None }
1403
1414
1404
- # Include each of the `unique_together` field names,
1415
+ # Include each of the `unique_together` and `UniqueConstraint` field names,
1405
1416
# so long as all the field names are included on the serializer.
1406
- for parent_class in [model ] + list (model ._meta .parents ):
1407
- for unique_together_list in parent_class ._meta .unique_together :
1408
- if set (field_names ).issuperset (set (unique_together_list )):
1409
- unique_constraint_names |= set (unique_together_list )
1417
+ for unique_together_list , queryset in self .get_unique_together_constraints (model ):
1418
+ if set (field_names ).issuperset (set (unique_together_list )):
1419
+ unique_constraint_names |= set (unique_together_list )
1410
1420
1411
1421
# Now we have all the field names that have uniqueness constraints
1412
1422
# applied, we can add the extra 'required=...' or 'default=...'
@@ -1503,11 +1513,6 @@ def get_unique_together_validators(self):
1503
1513
"""
1504
1514
Determine a default set of validators for any unique_together constraints.
1505
1515
"""
1506
- model_class_inheritance_tree = (
1507
- [self .Meta .model ] +
1508
- list (self .Meta .model ._meta .parents )
1509
- )
1510
-
1511
1516
# The field names we're passing though here only include fields
1512
1517
# which may map onto a model field. Any dotted field name lookups
1513
1518
# cannot map to a field, and must be a traversal, so we're not
@@ -1533,34 +1538,35 @@ def get_unique_together_validators(self):
1533
1538
# Note that we make sure to check `unique_together` both on the
1534
1539
# base model class, but also on any parent classes.
1535
1540
validators = []
1536
- for parent_class in model_class_inheritance_tree :
1537
- for unique_together in parent_class ._meta .unique_together :
1538
- # Skip if serializer does not map to all unique together sources
1539
- if not set (source_map ).issuperset (set (unique_together )):
1540
- continue
1541
-
1542
- for source in unique_together :
1543
- assert len (source_map [source ]) == 1 , (
1544
- "Unable to create `UniqueTogetherValidator` for "
1545
- "`{model}.{field}` as `{serializer}` has multiple "
1546
- "fields ({fields}) that map to this model field. "
1547
- "Either remove the extra fields, or override "
1548
- "`Meta.validators` with a `UniqueTogetherValidator` "
1549
- "using the desired field names."
1550
- .format (
1551
- model = self .Meta .model .__name__ ,
1552
- serializer = self .__class__ .__name__ ,
1553
- field = source ,
1554
- fields = ', ' .join (source_map [source ]),
1555
- )
1556
- )
1541
+ for unique_together , queryset in self .get_unique_together_constraints (self .Meta .model ):
1542
+ if len (unique_together ) < 2 :
1543
+ continue
1544
+ # Skip if serializer does not map to all unique together sources
1545
+ if not set (source_map ).issuperset (set (unique_together )):
1546
+ continue
1557
1547
1558
- field_names = tuple (source_map [f ][0 ] for f in unique_together )
1559
- validator = UniqueTogetherValidator (
1560
- queryset = parent_class ._default_manager ,
1561
- fields = field_names
1548
+ for source in unique_together :
1549
+ assert len (source_map [source ]) == 1 , (
1550
+ "Unable to create `UniqueTogetherValidator` for "
1551
+ "`{model}.{field}` as `{serializer}` has multiple "
1552
+ "fields ({fields}) that map to this model field. "
1553
+ "Either remove the extra fields, or override "
1554
+ "`Meta.validators` with a `UniqueTogetherValidator` "
1555
+ "using the desired field names."
1556
+ .format (
1557
+ model = self .Meta .model .__name__ ,
1558
+ serializer = self .__class__ .__name__ ,
1559
+ field = source ,
1560
+ fields = ', ' .join (source_map [source ]),
1561
+ )
1562
1562
)
1563
- validators .append (validator )
1563
+
1564
+ field_names = tuple (source_map [f ][0 ] for f in unique_together )
1565
+ validator = UniqueTogetherValidator (
1566
+ queryset = queryset ,
1567
+ fields = field_names
1568
+ )
1569
+ validators .append (validator )
1564
1570
return validators
1565
1571
1566
1572
def get_unique_for_date_validators (self ):
0 commit comments