@@ -1373,6 +1373,17 @@ def get_extra_kwargs(self):
13731373
13741374 return extra_kwargs
13751375
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+
13761387 def get_uniqueness_extra_kwargs (self , field_names , declared_fields , extra_kwargs ):
13771388 """
13781389 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
14011412
14021413 unique_constraint_names -= {None }
14031414
1404- # Include each of the `unique_together` field names,
1415+ # Include each of the `unique_together` and `UniqueConstraint` field names,
14051416 # 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 )
14101420
14111421 # Now we have all the field names that have uniqueness constraints
14121422 # applied, we can add the extra 'required=...' or 'default=...'
@@ -1503,11 +1513,6 @@ def get_unique_together_validators(self):
15031513 """
15041514 Determine a default set of validators for any unique_together constraints.
15051515 """
1506- model_class_inheritance_tree = (
1507- [self .Meta .model ] +
1508- list (self .Meta .model ._meta .parents )
1509- )
1510-
15111516 # The field names we're passing though here only include fields
15121517 # which may map onto a model field. Any dotted field name lookups
15131518 # cannot map to a field, and must be a traversal, so we're not
@@ -1533,34 +1538,35 @@ def get_unique_together_validators(self):
15331538 # Note that we make sure to check `unique_together` both on the
15341539 # base model class, but also on any parent classes.
15351540 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
15571547
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+ )
15621562 )
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 )
15641570 return validators
15651571
15661572 def get_unique_for_date_validators (self ):
0 commit comments