Skip to content

Commit d4e4043

Browse files
committed
Fix unique together validation.
While building validator unique together fields were compared with declared field names instead of model field names
1 parent 33d59fe commit d4e4043

File tree

2 files changed

+39
-1
lines changed

2 files changed

+39
-1
lines changed

rest_framework/serializers.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1469,12 +1469,13 @@ def get_uniqueness_extra_kwargs(self, field_names, declared_fields, extra_kwargs
14691469
model_field.unique_for_year}
14701470

14711471
unique_constraint_names -= {None}
1472+
model_fields_names = set(model_fields.keys())
14721473

14731474
# Include each of the `unique_together` and `UniqueConstraint` field names,
14741475
# so long as all the field names are included on the serializer.
14751476
for unique_together_list, queryset, condition_fields, condition in self.get_unique_together_constraints(model):
14761477
unique_together_list_and_condition_fields = set(unique_together_list) | set(condition_fields)
1477-
if set(field_names).issuperset(unique_together_list_and_condition_fields):
1478+
if model_fields_names.issuperset(unique_together_list_and_condition_fields):
14781479
unique_constraint_names |= unique_together_list_and_condition_fields
14791480

14801481
# Now we have all the field names that have uniqueness constraints

tests/test_validators.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,43 @@ def filter(self, **kwargs):
516516
validator.filter_queryset(attrs=data, queryset=queryset, serializer=serializer)
517517
assert queryset.called_with == {'race_name': 'bar', 'position': 1}
518518

519+
def test_uniq_together_validation_uses_model_fields_method_field(self):
520+
class TestSerializer(serializers.ModelSerializer):
521+
position = serializers.SerializerMethodField()
522+
523+
def get_position(self, obj):
524+
return obj.position or 0
525+
526+
class Meta:
527+
model = NullUniquenessTogetherModel
528+
fields = ['race_name', 'position']
529+
530+
serializer = TestSerializer()
531+
expected = dedent("""
532+
TestSerializer():
533+
race_name = CharField(max_length=100)
534+
position = SerializerMethodField()
535+
""")
536+
assert repr(serializer) == expected
537+
538+
def test_uniq_together_validation_uses_model_fields_with_source_field(self):
539+
class TestSerializer(serializers.ModelSerializer):
540+
pos = serializers.IntegerField(source='position')
541+
542+
class Meta:
543+
model = NullUniquenessTogetherModel
544+
fields = ['race_name', 'pos']
545+
546+
serializer = TestSerializer()
547+
expected = dedent("""
548+
TestSerializer():
549+
race_name = CharField(max_length=100, required=True)
550+
pos = IntegerField(source='position')
551+
class Meta:
552+
validators = [<UniqueTogetherValidator(queryset=NullUniquenessTogetherModel.objects.all(), fields=('race_name', 'pos'))>]
553+
""")
554+
assert repr(serializer) == expected
555+
519556

520557
class UniqueConstraintModel(models.Model):
521558
race_name = models.CharField(max_length=100)

0 commit comments

Comments
 (0)