Skip to content

Commit 41edb3b

Browse files
authored
Avoid unnecessary unique together checking (#9154)
1 parent 2797c0f commit 41edb3b

File tree

2 files changed

+30
-5
lines changed

2 files changed

+30
-5
lines changed

rest_framework/validators.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -160,10 +160,19 @@ def __call__(self, attrs, serializer):
160160
queryset = self.exclude_current_instance(attrs, queryset, serializer.instance)
161161

162162
# Ignore validation if any field is None
163-
checked_values = [
164-
value for field, value in attrs.items() if field in self.fields
165-
]
166-
if None not in checked_values and qs_exists(queryset):
163+
if serializer.instance is None:
164+
checked_values = [
165+
value for field, value in attrs.items() if field in self.fields
166+
]
167+
else:
168+
# Ignore validation if all field values are unchanged
169+
checked_values = [
170+
value
171+
for field, value in attrs.items()
172+
if field in self.fields and value != getattr(serializer.instance, field)
173+
]
174+
175+
if checked_values and None not in checked_values and qs_exists(queryset):
167176
field_names = ', '.join(self.fields)
168177
message = self.message.format(field_names=field_names)
169178
raise ValidationError(message, code='unique')

tests/test_validators.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import datetime
2-
from unittest.mock import MagicMock
2+
from unittest.mock import MagicMock, patch
33

44
import pytest
55
from django.db import DataError, models
@@ -447,6 +447,22 @@ def test_do_not_ignore_validation_for_null_fields(self):
447447
serializer = NullUniquenessTogetherSerializer(data=data)
448448
assert not serializer.is_valid()
449449

450+
def test_ignore_validation_for_unchanged_fields(self):
451+
"""
452+
If all fields in the unique together constraint are unchanged,
453+
then the instance should skip uniqueness validation.
454+
"""
455+
instance = UniquenessTogetherModel.objects.create(
456+
race_name="Paris Marathon", position=1
457+
)
458+
data = {"race_name": "Paris Marathon", "position": 1}
459+
serializer = UniquenessTogetherSerializer(data=data, instance=instance)
460+
with patch(
461+
"rest_framework.validators.qs_exists"
462+
) as mock:
463+
assert serializer.is_valid()
464+
assert not mock.called
465+
450466
def test_filter_queryset_do_not_skip_existing_attribute(self):
451467
"""
452468
filter_queryset should add value from existing instance attribute

0 commit comments

Comments
 (0)