diff --git a/rest_framework/validators.py b/rest_framework/validators.py index 1cbe31b5ea..3cce18f3fe 100644 --- a/rest_framework/validators.py +++ b/rest_framework/validators.py @@ -107,6 +107,7 @@ def set_context(self, serializer): """ # Determine the existing instance, if this is an update operation. self.instance = getattr(serializer, 'instance', None) + self.serializer = serializer def enforce_required_fields(self, attrs): """ @@ -133,12 +134,24 @@ def filter_queryset(self, attrs, queryset): if self.instance is not None: for field_name in self.fields: if field_name not in attrs: - attrs[field_name] = getattr(self.instance, field_name) + if field_name == self.serializer.fields[field_name].source: + attrs[field_name] = getattr(self.instance, field_name) + else: + attrs[self.serializer.fields[field_name].source] = getattr(self.instance, self.serializer.fields[field_name].source) + # Determine the filter keyword arguments and filter the queryset. filter_kwargs = { - field_name: attrs[field_name] - for field_name in self.fields + ( + field_name + if field_name == self.serializer.fields[field_name].source + else self.serializer.fields[field_name].source + ): ( + attrs[field_name] + if self.instance is None or not self.serializer.partial + else attrs[self.serializer.fields[field_name].source] + ) + for field_name in self.fields } return qs_filter(queryset, **filter_kwargs) diff --git a/tests/test_validators.py b/tests/test_validators.py index fe31ba2357..6b02d32643 100644 --- a/tests/test_validators.py +++ b/tests/test_validators.py @@ -365,6 +365,40 @@ def filter(self, **kwargs): validator.filter_queryset(attrs=data, queryset=queryset) assert queryset.called_with == {'race_name': 'bar', 'position': 1} +class WritableFieldsWithSourceSerializer(serializers.ModelSerializer): + name = serializers.CharField(source='race_name') + + class Meta: + model = UniquenessTogetherModel + fields = ['name', 'position'] + validators = [ + UniqueTogetherValidator( + queryset=UniquenessTogetherModel.objects.all(), + fields=['name', 'position'] + ) + ] + +class ReadOnlyFieldsWithSourceSerializer(serializers.ModelSerializer): + name = serializers.CharField(source='race_name', read_only=True, default='test') + + class Meta: + model = UniquenessTogetherModel + fields = ['name', 'position'] + validators = [ + UniqueTogetherValidator( + queryset=UniquenessTogetherModel.objects.all(), + fields=['name', 'position'] + ) + ] + +class TestFieldsWithFieldSource(TestCase): + def test_writeable(self): + serializer = WritableFieldsWithSourceSerializer(data={'name': 'formula1', 'position': '1'}) + serializer.is_valid(raise_exception=True) + + def test_read_only(self): + serializer = ReadOnlyFieldsWithSourceSerializer(data={'position': '1'}) + serializer.is_valid(raise_exception=True) # Tests for `UniqueForDateValidator` # ----------------------------------