From 00148d545cbbaf4d2806e55479d5f67adf1b322e Mon Sep 17 00:00:00 2001 From: Brad MacPhee Date: Wed, 21 Sep 2016 11:37:53 -0300 Subject: [PATCH] Add support for models with custom primary key - serializer can treat primary key field as read-only during update, but accept it as writable during create when it is not auto-generated --- rest_framework/serializers.py | 6 ++++-- tests/test_model_serializer.py | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index 59533be1e..c472f4c17 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -994,7 +994,7 @@ class ModelSerializer(Serializer): # Determine any extra field arguments and hidden fields that # should be included - extra_kwargs = self.get_extra_kwargs() + extra_kwargs = self.get_extra_kwargs(info) extra_kwargs, hidden_fields = self.get_uniqueness_extra_kwargs( field_names, declared_fields, extra_kwargs ) @@ -1289,7 +1289,7 @@ class ModelSerializer(Serializer): # Methods for determining additional keyword arguments to apply... - def get_extra_kwargs(self): + def get_extra_kwargs(self, model_info): """ Return a dictionary mapping field names to a dictionary of additional keyword arguments. @@ -1317,6 +1317,8 @@ class ModelSerializer(Serializer): (self.__class__.__module__, self.__class__.__name__) ) + if not model_info.pk.auto_created and self.instance: + extra_kwargs.setdefault(model_info.pk.name, {})['read_only'] = True return extra_kwargs def get_uniqueness_extra_kwargs(self, field_names, declared_fields, extra_kwargs): diff --git a/tests/test_model_serializer.py b/tests/test_model_serializer.py index 203e1fe7f..25da087c6 100644 --- a/tests/test_model_serializer.py +++ b/tests/test_model_serializer.py @@ -42,6 +42,10 @@ class OneFieldModel(models.Model): char_field = models.CharField(max_length=100) +class CustomPrimaryKeyModel(models.Model): + char_field = models.CharField(primary_key=True, max_length=100) + + class RegularFieldsModel(models.Model): """ A model class for testing regular flat fields. @@ -153,6 +157,34 @@ class TestModelSerializer(TestCase): assert str(excinfo.exception).startswith(msginitial) +class TestCustomPrimaryKeyModelSerializer(TestCase): + class TestSerializer(serializers.ModelSerializer): + class Meta: + model = CustomPrimaryKeyModel + fields = ('char_field',) + + def test_create_method(self): + serializer = self.TestSerializer(data={ + 'char_field': 'foo' + }) + assert serializer.is_valid() + instance = serializer.save() + assert 'foo' == instance.pk + + def test_pk_read_only_on_update(self): + instance = CustomPrimaryKeyModel.objects.create( + char_field='foo' + ) + instance.save() + + serializer = self.TestSerializer(instance=instance, data={ + 'char_field': 'bar' + }) + assert serializer.is_valid() + updated_instance = serializer.save() + assert 'bar' != updated_instance.pk + + class TestRegularFieldMappings(TestCase): def test_regular_fields(self): """