diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index a4b51ae9d..c1dc67155 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -909,8 +909,14 @@ class ModelSerializer(Serializer): info = model_meta.get_field_info(ModelClass) many_to_many = {} for field_name, relation_info in info.relations.items(): - if relation_info.to_many and (field_name in validated_data): - many_to_many[field_name] = validated_data.pop(field_name) + if field_name in validated_data: + if relation_info.to_many: + many_to_many[field_name] = validated_data.pop(field_name) + elif not isinstance( + validated_data[field_name], + relation_info.related_model): + validated_data[relation_info.model_field.attname] = \ + validated_data.pop(field_name) try: instance = ModelClass.objects.create(**validated_data) @@ -1368,7 +1374,7 @@ class ModelSerializer(Serializer): elif getattr(unique_constraint_field, 'auto_now', None): default = timezone.now elif unique_constraint_field.has_default(): - default = unique_constraint_field.default + default = unique_constraint_field.get_default() else: default = empty diff --git a/tests/models.py b/tests/models.py index 6c9dde8fa..7ea44c650 100644 --- a/tests/models.py +++ b/tests/models.py @@ -61,6 +61,19 @@ class ForeignKeySource(RESTFrameworkModel): on_delete=models.CASCADE) +class ForeignKeyInUniquenessConstraintSource(RESTFrameworkModel): + name = models.CharField(max_length=100) + target = models.ForeignKey(ForeignKeyTarget, + related_name='sources_with_uniqueness', + help_text='Target', + verbose_name='Target', + default=1, + on_delete=models.CASCADE) + + class Meta: + unique_together = ('name', 'target') + + # Nullable ForeignKey class NullableForeignKeySource(RESTFrameworkModel): name = models.CharField(max_length=100) diff --git a/tests/test_relations_pk.py b/tests/test_relations_pk.py index 2eebe1b5c..cdc7f2aa2 100644 --- a/tests/test_relations_pk.py +++ b/tests/test_relations_pk.py @@ -5,8 +5,9 @@ from django.utils import six from rest_framework import serializers from tests.models import ( - ForeignKeySource, ForeignKeyTarget, ManyToManySource, ManyToManyTarget, - NullableForeignKeySource, NullableOneToOneSource, NullableUUIDForeignKeySource, + ForeignKeyInUniquenessConstraintSource, ForeignKeySource, ForeignKeyTarget, + ManyToManySource, ManyToManyTarget, NullableForeignKeySource, + NullableOneToOneSource, NullableUUIDForeignKeySource, OneToOnePKSource, OneToOneTarget, UUIDForeignKeyTarget ) @@ -37,6 +38,12 @@ class ForeignKeySourceSerializer(serializers.ModelSerializer): fields = ('id', 'name', 'target') +class ForeignKeyUniquenessSourceSerializer(serializers.ModelSerializer): + class Meta: + model = ForeignKeyInUniquenessConstraintSource + fields = ('id', 'name', 'target') + + # Nullable ForeignKey class NullableForeignKeySourceSerializer(serializers.ModelSerializer): class Meta: @@ -360,6 +367,35 @@ class PKForeignKeyTests(TestCase): assert 'target' not in serializer.validated_data +class PKForeignKeyInUniquenessConstraintTests(TestCase): + def test_use_default_value_for_fk(self): + default_val = ForeignKeyInUniquenessConstraintSource._meta.get_field( + 'target' + ).default + target = ForeignKeyTarget.objects.create(pk=default_val) + serializer = ForeignKeyUniquenessSourceSerializer( + data={'name': 'source-1'} + ) + assert serializer.is_valid() + serializer.save() + source = ForeignKeyInUniquenessConstraintSource.objects.get( + name='source-1', + ) + assert source.target == target + + def test_provide_value_for_fk(self): + target = ForeignKeyTarget.objects.create(pk=10) + serializer = ForeignKeyUniquenessSourceSerializer( + data={'name': 'source-2', 'target': target.pk} + ) + assert serializer.is_valid() + serializer.save() + source = ForeignKeyInUniquenessConstraintSource.objects.get( + name='source-2', + ) + assert source.target == target + + class PKNullableForeignKeyTests(TestCase): def setUp(self): target = ForeignKeyTarget(name='target-1')