diff --git a/rest_framework/validators.py b/rest_framework/validators.py index 4c444cf01e..76d2a2159f 100644 --- a/rest_framework/validators.py +++ b/rest_framework/validators.py @@ -189,7 +189,12 @@ def __call__(self, attrs, serializer): ] condition_sources = (serializer.fields[field_name].source for field_name in self.condition_fields) - condition_kwargs = {source: attrs[source] for source in condition_sources} + condition_kwargs = { + source: attrs[source] + if source in attrs + else getattr(serializer.instance, source) + for source in condition_sources + } if checked_values and None not in checked_values and qs_exists_with_condition(queryset, self.condition, condition_kwargs): field_names = ', '.join(self.fields) message = self.message.format(field_names=field_names) diff --git a/tests/test_validators.py b/tests/test_validators.py index c594eecbe5..ea5bf3a4dd 100644 --- a/tests/test_validators.py +++ b/tests/test_validators.py @@ -589,6 +589,21 @@ class Meta: ] +class UniqueConstraintReadOnlyFieldModel(models.Model): + state = models.CharField(max_length=100, default="new") + position = models.IntegerField() + something = models.IntegerField() + + class Meta: + constraints = [ + models.UniqueConstraint( + name="unique_constraint_%(class)s", + fields=("position", "something"), + condition=models.Q(state="new"), + ), + ] + + class UniqueConstraintNullableModel(models.Model): title = models.CharField(max_length=100) age = models.IntegerField(null=True) @@ -738,6 +753,31 @@ class Meta: ) assert serializer.is_valid() + def test_uniq_constraint_condition_read_only_create(self): + class UniqueConstraintReadOnlyFieldModelSerializer(serializers.ModelSerializer): + class Meta: + model = UniqueConstraintReadOnlyFieldModel + read_only_fields = ("state",) + fields = ("position", "something", *read_only_fields) + serializer = UniqueConstraintReadOnlyFieldModelSerializer( + data={"position": 1, "something": 1} + ) + assert serializer.is_valid() + + def test_uniq_constraint_condition_read_only_partial(self): + class UniqueConstraintReadOnlyFieldModelSerializer(serializers.ModelSerializer): + class Meta: + model = UniqueConstraintReadOnlyFieldModel + read_only_fields = ("state",) + fields = ("position", "something", *read_only_fields) + instance = UniqueConstraintReadOnlyFieldModel.objects.create(position=1, something=1) + serializer = UniqueConstraintReadOnlyFieldModelSerializer( + instance=instance, + data={"position": 1, "something": 1}, + partial=True + ) + assert serializer.is_valid() + # Tests for `UniqueForDateValidator` # ----------------------------------