Skip to content

Commit 2d20f09

Browse files
committed
Merge pull request #4146 from xiaohanyu/bug-fix-unique-validator-error-with-related-field
Fix #3844, refine validator for fields with <source=> kwargs
2 parents 35ace2e + 19bdfda commit 2d20f09

File tree

2 files changed

+28
-3
lines changed

2 files changed

+28
-3
lines changed

rest_framework/validators.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ def set_context(self, serializer_field):
3535
"""
3636
# Determine the underlying model field name. This may not be the
3737
# same as the serializer field name if `source=<>` is set.
38-
self.field_name = serializer_field.source_attrs[0]
38+
self.field_name = serializer_field.source_attrs[-1]
3939
# Determine the existing instance, if this is an update operation.
4040
self.instance = getattr(serializer_field.parent, 'instance', None)
4141

@@ -174,8 +174,8 @@ def set_context(self, serializer):
174174
"""
175175
# Determine the underlying model field names. These may not be the
176176
# same as the serializer field names if `source=<>` is set.
177-
self.field_name = serializer.fields[self.field].source_attrs[0]
178-
self.date_field_name = serializer.fields[self.date_field].source_attrs[0]
177+
self.field_name = serializer.fields[self.field].source_attrs[-1]
178+
self.date_field_name = serializer.fields[self.date_field].source_attrs[-1]
179179
# Determine the existing instance, if this is an update operation.
180180
self.instance = getattr(serializer, 'instance', None)
181181

tests/test_validators.py

+25
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from django.test import TestCase
55

66
from rest_framework import serializers
7+
from rest_framework.validators import UniqueValidator
78

89

910
def dedent(blocktext):
@@ -22,6 +23,20 @@ class Meta:
2223
model = UniquenessModel
2324

2425

26+
class RelatedModel(models.Model):
27+
user = models.OneToOneField(UniquenessModel, on_delete=models.CASCADE)
28+
email = models.CharField(unique=True, max_length=80)
29+
30+
31+
class RelatedModelSerializer(serializers.ModelSerializer):
32+
username = serializers.CharField(source='user.username',
33+
validators=[UniqueValidator(queryset=UniquenessModel.objects.all())]) # NOQA
34+
35+
class Meta:
36+
model = RelatedModel
37+
fields = ('username', 'email')
38+
39+
2540
class AnotherUniquenessModel(models.Model):
2641
code = models.IntegerField(unique=True)
2742

@@ -73,6 +88,16 @@ def test_doesnt_pollute_model(self):
7388
self.assertEqual(
7489
AnotherUniquenessModel._meta.get_field('code').validators, [])
7590

91+
def test_related_model_is_unique(self):
92+
data = {'username': 'existing', 'email': '[email protected]'}
93+
rs = RelatedModelSerializer(data=data)
94+
self.assertFalse(rs.is_valid())
95+
self.assertEqual(rs.errors,
96+
{'username': ['This field must be unique.']})
97+
data = {'username': 'new-username', 'email': '[email protected]'}
98+
rs = RelatedModelSerializer(data=data)
99+
self.assertTrue(rs.is_valid())
100+
76101

77102
# Tests for `UniqueTogetherValidator`
78103
# -----------------------------------

0 commit comments

Comments
 (0)