diff --git a/rest_framework/validators.py b/rest_framework/validators.py index 3f09c15cd..71ebc2ca9 100644 --- a/rest_framework/validators.py +++ b/rest_framework/validators.py @@ -159,17 +159,18 @@ class UniqueTogetherValidator: queryset = self.filter_queryset(attrs, queryset, serializer) queryset = self.exclude_current_instance(attrs, queryset, serializer.instance) + checked_names = [ + serializer.fields[field_name].source for field_name in self.fields + ] # Ignore validation if any field is None if serializer.instance is None: - checked_values = [ - value for field, value in attrs.items() if field in self.fields - ] + checked_values = [attrs[field_name] for field_name in checked_names] else: # Ignore validation if all field values are unchanged checked_values = [ - value - for field, value in attrs.items() - if field in self.fields and value != getattr(serializer.instance, field) + attrs[field_name] + for field_name in checked_names + if attrs[field_name] != getattr(serializer.instance, field_name) ] if checked_values and None not in checked_values and qs_exists(queryset): diff --git a/tests/test_validators.py b/tests/test_validators.py index c38dc1134..4bb8658d5 100644 --- a/tests/test_validators.py +++ b/tests/test_validators.py @@ -469,6 +469,28 @@ class TestUniquenessTogetherValidation(TestCase): assert serializer.is_valid() assert not mock.called + @patch("rest_framework.validators.qs_exists") + def test_unique_together_with_source(self, mock_qs_exists): + class UniqueTogetherWithSourceSerializer(serializers.ModelSerializer): + name = serializers.CharField(source="race_name") + pos = serializers.IntegerField(source="position") + + class Meta: + model = UniquenessTogetherModel + fields = ["name", "pos"] + + data = {"name": "Paris Marathon", "pos": 1} + instance = UniquenessTogetherModel.objects.create( + race_name="Paris Marathon", position=1 + ) + serializer = UniqueTogetherWithSourceSerializer(data=data) + assert not serializer.is_valid() + assert mock_qs_exists.called + mock_qs_exists.reset_mock() + serializer = UniqueTogetherWithSourceSerializer(data=data, instance=instance) + assert serializer.is_valid() + assert not mock_qs_exists.called + def test_filter_queryset_do_not_skip_existing_attribute(self): """ filter_queryset should add value from existing instance attribute