diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index 3fcc85c3b..7883bd80d 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -947,6 +947,11 @@ class ModelSerializer(Serializer): # Determine any extra field arguments and hidden fields that # should be included extra_kwargs = self.get_extra_kwargs() + for field in extra_kwargs: + assert field not in declared_fields, ( + "Field {} is declared on the class and also present in " + "extra_kwargs or read_only_fields".format(field) + ) extra_kwargs, hidden_fields = self.get_uniqueness_extra_kwargs( field_names, declared_fields, extra_kwargs ) @@ -1321,12 +1326,11 @@ class ModelSerializer(Serializer): # add in a hidden field that populates it. hidden_fields[unique_constraint_name] = HiddenField(default=default) - # Update `extra_kwargs` with any new options. + # Update `extra_kwargs` with any new options but don't overwrite old values. for key, value in uniqueness_extra_kwargs.items(): if key in extra_kwargs: - extra_kwargs[key].update(value) - else: - extra_kwargs[key] = value + value.update(extra_kwargs[key]) + extra_kwargs[key] = value return extra_kwargs, hidden_fields diff --git a/tests/test_model_serializer.py b/tests/test_model_serializer.py index 096cbc8d6..b812a6791 100644 --- a/tests/test_model_serializer.py +++ b/tests/test_model_serializer.py @@ -933,8 +933,8 @@ class TestMetaInheritance(TestCase): class Meta: model = OneFieldModel - read_only_fields = ('char_field', 'non_model_field') - fields = read_only_fields + read_only_fields = ('char_field',) + fields = read_only_fields + ('non_model_field', ) extra_kwargs = {} class ChildSerializer(TestSerializer): @@ -955,3 +955,44 @@ class TestMetaInheritance(TestCase): self.assertEqual(unicode_repr(ChildSerializer()), child_expected) self.assertEqual(unicode_repr(TestSerializer()), test_expected) self.assertEqual(unicode_repr(ChildSerializer()), child_expected) + + +class TestDeclaredFieldsConflict(TestCase): + def test_extra_kwargs_conflict(self): + class TestSerializer(serializers.ModelSerializer): + some_field = serializers.CharField() + + class Meta: + model = OneFieldModel + extra_kwargs = {'some_field': {'read_only': True}} + with self.assertRaises(AssertionError): + TestSerializer().get_fields() + + def test_read_only_fields_conflict(self): + class TestSerializer(serializers.ModelSerializer): + some_field = serializers.CharField() + + class Meta: + model = OneFieldModel + read_only_fields = ('some_field', ) + with self.assertRaises(AssertionError): + TestSerializer().get_fields() + + +class TestUniquenessOverride(TestCase): + def test_required_not_overwritten(self): + class TestModel(models.Model): + field_1 = models.IntegerField(null=True) + field_2 = models.IntegerField() + + class Meta: + unique_together = (('field_1', 'field_2'),) + + class TestSerializer(serializers.ModelSerializer): + class Meta: + model = TestModel + extra_kwargs = {'field_1': {'required': False}} + + fields = TestSerializer().fields + self.assertFalse(fields['field_1'].required) + self.assertTrue(fields['field_2'].required)