Skip to content

Commit fd7db77

Browse files
committed
Bring UniqueValidator implementation in line with other uniquness validators.
1 parent 8c1fa0b commit fd7db77

File tree

2 files changed

+21
-7
lines changed

2 files changed

+21
-7
lines changed

docs/api-guide/validators.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ Validation in Django REST framework serializers is handled a little differently
1616

1717
With `ModelForm` the validation is performed partially on the form, and partially on the model instance. With REST framework the validation is performed entirely on the serializer class. This is advantageous for the following reasons:
1818

19-
* It introduces a proper separation of concerns, making your code behaviour more obvious.
20-
* It is easy to switch between using shortcut `ModelSerializer` classes and using explicit `Serializer` classes. Any validation behaviour being used for `ModelSerializer` is simple to replicate.
21-
* Printing the `repr` of a serializer instance will show you exactly what validation rules it applies. There's no extra hidden validation behaviour being called on the model instance.
19+
* It introduces a proper separation of concerns, making your code behavior more obvious.
20+
* It is easy to switch between using shortcut `ModelSerializer` classes and using explicit `Serializer` classes. Any validation behavior being used for `ModelSerializer` is simple to replicate.
21+
* Printing the `repr` of a serializer instance will show you exactly what validation rules it applies. There's no extra hidden validation behavior being called on the model instance.
2222

2323
When you're using `ModelSerializer` all of this is handled automatically for you. If you want to drop down to using a `Serializer` classes instead, then you need to define the validation rules explicitly.
2424

rest_framework/validators.py

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,26 @@ def set_context(self, serializer_field):
3535
# Determine the existing instance, if this is an update operation.
3636
self.instance = getattr(serializer_field.parent, 'instance', None)
3737

38-
def __call__(self, value):
39-
# Ensure uniqueness.
38+
def filter_queryset(self, value, queryset):
39+
"""
40+
Filter the queryset to all instances matching the given attribute.
41+
"""
4042
filter_kwargs = {self.field_name: value}
41-
queryset = self.queryset.filter(**filter_kwargs)
43+
return queryset.filter(**filter_kwargs)
44+
45+
def exclude_current_instance(self, queryset):
46+
"""
47+
If an instance is being updated, then do not include
48+
that instance itself as a uniqueness conflict.
49+
"""
4250
if self.instance is not None:
43-
queryset = queryset.exclude(pk=self.instance.pk)
51+
return queryset.exclude(pk=self.instance.pk)
52+
return queryset
53+
54+
def __call__(self, value):
55+
queryset = self.queryset
56+
queryset = self.filter_queryset(value, queryset)
57+
queryset = self.exclude_current_instance(queryset)
4458
if queryset.exists():
4559
raise ValidationError(self.message)
4660

0 commit comments

Comments
 (0)