From 053eb1e213c7369cab4de683d7128a90b7a10089 Mon Sep 17 00:00:00 2001 From: Nicolas Delaby Date: Tue, 12 Aug 2025 17:08:28 +0200 Subject: [PATCH] Condition of UniqueValidator can be read-only We can't always expect to find the value of the condition in the serializer if the field is read-only. --- rest_framework/validators.py | 7 ++++++- tests/test_validators.py | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/rest_framework/validators.py b/rest_framework/validators.py index 4c444cf01..76d2a2159 100644 --- a/rest_framework/validators.py +++ b/rest_framework/validators.py @@ -189,7 +189,12 @@ class UniqueTogetherValidator: ] 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 c594eecbe..15f30f1c0 100644 --- a/tests/test_validators.py +++ b/tests/test_validators.py @@ -589,6 +589,21 @@ class UniqueConstraintModel(models.Model): ] +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,23 @@ class TestUniqueConstraintValidation(TestCase): ) assert serializer.is_valid() + def test_uniq_constraint_condition_read_only(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() + UniqueConstraintReadOnlyFieldModel.objects.create(position=1, something=1) + serializer = UniqueConstraintReadOnlyFieldModelSerializer( + data={"position": 1, "something": 1} + ) + assert not serializer.is_valid() + # Tests for `UniqueForDateValidator` # ----------------------------------