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

Lines changed: 3 additions & 3 deletions
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

Lines changed: 25 additions & 0 deletions
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': 'new-email@example.com'}
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': 'new-email@example.com'}
98+
rs = RelatedModelSerializer(data=data)
99+
self.assertTrue(rs.is_valid())
100+
76101

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

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy