@@ -1396,6 +1396,23 @@ def get_extra_kwargs(self):
13961396
13971397 return extra_kwargs
13981398
1399+ def get_unique_together_constraints (self , model ):
1400+ """
1401+ Returns iterator of (fields, queryset), each entry describe an unique together
1402+ constraint on `fields` in `queryset`.
1403+ """
1404+ for parent_class in [model ] + list (model ._meta .parents ):
1405+ for unique_together in parent_class ._meta .unique_together :
1406+ yield unique_together , model ._default_manager
1407+ for constraint in parent_class ._meta .constraints :
1408+ if isinstance (constraint , models .UniqueConstraint ) and len (constraint .fields ) > 1 :
1409+ yield (
1410+ constraint .fields ,
1411+ model ._default_manager
1412+ if constraint .condition is None
1413+ else model ._default_manager .filter (constraint .condition )
1414+ )
1415+
13991416 def get_uniqueness_extra_kwargs (self , field_names , declared_fields , extra_kwargs ):
14001417 """
14011418 Return any additional field options that need to be included as a
@@ -1424,12 +1441,11 @@ def get_uniqueness_extra_kwargs(self, field_names, declared_fields, extra_kwargs
14241441
14251442 unique_constraint_names -= {None }
14261443
1427- # Include each of the `unique_together` field names,
1444+ # Include each of the `unique_together` and `UniqueConstraint` field names,
14281445 # so long as all the field names are included on the serializer.
1429- for parent_class in [model ] + list (model ._meta .parents ):
1430- for unique_together_list in parent_class ._meta .unique_together :
1431- if set (field_names ).issuperset (unique_together_list ):
1432- unique_constraint_names |= set (unique_together_list )
1446+ for unique_together_list , _ in self .get_unique_together_constraints (model ):
1447+ if set (field_names ).issuperset (unique_together_list ):
1448+ unique_constraint_names |= set (unique_together_list )
14331449
14341450 # Now we have all the field names that have uniqueness constraints
14351451 # applied, we can add the extra 'required=...' or 'default=...'
@@ -1526,11 +1542,6 @@ def get_unique_together_validators(self):
15261542 """
15271543 Determine a default set of validators for any unique_together constraints.
15281544 """
1529- model_class_inheritance_tree = (
1530- [self .Meta .model ] +
1531- list (self .Meta .model ._meta .parents )
1532- )
1533-
15341545 # The field names we're passing though here only include fields
15351546 # which may map onto a model field. Any dotted field name lookups
15361547 # cannot map to a field, and must be a traversal, so we're not
@@ -1556,34 +1567,33 @@ def get_unique_together_validators(self):
15561567 # Note that we make sure to check `unique_together` both on the
15571568 # base model class, but also on any parent classes.
15581569 validators = []
1559- for parent_class in model_class_inheritance_tree :
1560- for unique_together in parent_class ._meta .unique_together :
1561- # Skip if serializer does not map to all unique together sources
1562- if not set (source_map ).issuperset (unique_together ):
1563- continue
1564-
1565- for source in unique_together :
1566- assert len (source_map [source ]) == 1 , (
1567- "Unable to create `UniqueTogetherValidator` for "
1568- "`{model}.{field}` as `{serializer}` has multiple "
1569- "fields ({fields}) that map to this model field. "
1570- "Either remove the extra fields, or override "
1571- "`Meta.validators` with a `UniqueTogetherValidator` "
1572- "using the desired field names."
1573- .format (
1574- model = self .Meta .model .__name__ ,
1575- serializer = self .__class__ .__name__ ,
1576- field = source ,
1577- fields = ', ' .join (source_map [source ]),
1578- )
1579- )
1570+ for unique_together , queryset in self .get_unique_together_constraints (self .Meta .model ):
1571+ # Skip if serializer does not map to all unique together sources
1572+ if not set (source_map ).issuperset (unique_together ):
1573+ continue
15801574
1581- field_names = tuple (source_map [f ][0 ] for f in unique_together )
1582- validator = UniqueTogetherValidator (
1583- queryset = parent_class ._default_manager ,
1584- fields = field_names
1575+ for source in unique_together :
1576+ assert len (source_map [source ]) == 1 , (
1577+ "Unable to create `UniqueTogetherValidator` for "
1578+ "`{model}.{field}` as `{serializer}` has multiple "
1579+ "fields ({fields}) that map to this model field. "
1580+ "Either remove the extra fields, or override "
1581+ "`Meta.validators` with a `UniqueTogetherValidator` "
1582+ "using the desired field names."
1583+ .format (
1584+ model = self .Meta .model .__name__ ,
1585+ serializer = self .__class__ .__name__ ,
1586+ field = source ,
1587+ fields = ', ' .join (source_map [source ]),
1588+ )
15851589 )
1586- validators .append (validator )
1590+
1591+ field_names = tuple (source_map [f ][0 ] for f in unique_together )
1592+ validator = UniqueTogetherValidator (
1593+ queryset = queryset ,
1594+ fields = field_names
1595+ )
1596+ validators .append (validator )
15871597 return validators
15881598
15891599 def get_unique_for_date_validators (self ):
0 commit comments