diff options
| author | Tom Christie | 2012-11-09 09:04:45 -0800 | 
|---|---|---|
| committer | Tom Christie | 2012-11-09 09:04:45 -0800 | 
| commit | da1aa5542cff3295d3a53821d4afe02911094181 (patch) | |
| tree | d40beff70dbc341d0a0b1bc38636a912276d2899 | |
| parent | b1b284cdbc7732b8825565cf70f8cc56f56971fc (diff) | |
| parent | e224061189a6a5ea2c063f3820239eed6c3a88fb (diff) | |
| download | django-rest-framework-da1aa5542cff3295d3a53821d4afe02911094181.tar.bz2 | |
Merge pull request #394 from tomchristie/read_only_fields
Read only fields
| -rw-r--r-- | docs/api-guide/serializers.md | 9 | ||||
| -rw-r--r-- | docs/index.md | 7 | ||||
| -rw-r--r-- | docs/topics/release-notes.md | 4 | ||||
| -rw-r--r-- | rest_framework/serializers.py | 7 | ||||
| -rw-r--r-- | rest_framework/tests/serializer.py | 19 | 
5 files changed, 41 insertions, 5 deletions
diff --git a/docs/api-guide/serializers.md b/docs/api-guide/serializers.md index 0cdae1ce..a9589144 100644 --- a/docs/api-guide/serializers.md +++ b/docs/api-guide/serializers.md @@ -248,6 +248,15 @@ The default `ModelSerializer` uses primary keys for relationships, but you can a  The `depth` option should be set to an integer value that indicates the depth of relationships that should be traversed before reverting to a flat representation. +## Specifying which fields should be read-only  + +You may wish to specify multiple fields as read-only. Instead of adding each field explicitely with the `read_only=True` attribute, you may use the `read_only_fields` Meta option, like so: + +    class AccountSerializer(serializers.ModelSerializer): +        class Meta: +            model = Account +            read_only_fields = ('created', 'modified') +  ## Customising the default fields  You can create customized subclasses of `ModelSerializer` that use a different set of default fields for the representation, by overriding various `get_<field_type>_field` methods. diff --git a/docs/index.md b/docs/index.md index 1874ec00..fd834540 100644 --- a/docs/index.md +++ b/docs/index.md @@ -32,7 +32,7 @@ REST framework requires the following:  The following packages are optional: -* [Markdown][markdown] (2.1.0+) - Markdown support for the self describing API. +* [Markdown][markdown] (2.1.0+) - Markdown support for the browseable API.  * [PyYAML][yaml] (3.10+) - YAML content-type support.  * [django-filter][django-filter] (master) - Filtering support. @@ -41,8 +41,9 @@ The following packages are optional:  Install using `pip`, including any optional packages you want...      pip install djangorestframework -    pip install markdown  # Recommended if using the browseable API. -    pip install pyyaml    # Required for yaml content-type support. +    pip install markdown  # Markdown support for the browseable API. +    pip install pyyaml    # YAML content-type support. +    pip install -e git+https://github.com/alex/django-filter.git#egg=django-filter  # Filtering support  ...or clone the project from github. diff --git a/docs/topics/release-notes.md b/docs/topics/release-notes.md index 670332e6..35e8a8b3 100644 --- a/docs/topics/release-notes.md +++ b/docs/topics/release-notes.md @@ -4,6 +4,10 @@  >  > — Eric S. Raymond, [The Cathedral and the Bazaar][cite]. +## Master + +* Support for `read_only_fields` on `ModelSerializer` classes. +  ## 2.1.2  **Date**: 9th Nov 2012 diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index 95145d58..329b38f2 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -321,6 +321,7 @@ class ModelSerializerOptions(SerializerOptions):      def __init__(self, meta):          super(ModelSerializerOptions, self).__init__(meta)          self.model = getattr(meta, 'model', None) +        self.read_only_fields = getattr(meta, 'read_only_fields', ())  class ModelSerializer(Serializer): @@ -369,6 +370,12 @@ class ModelSerializer(Serializer):                  field.initialize(parent=self, field_name=model_field.name)                  ret[model_field.name] = field +        for field_name in self.opts.read_only_fields: +            assert field_name in ret, \ +                "read_only_fields on '%s' included invalid item '%s'" % \ +                (self.__class__.__name__, field_name) +            ret[field_name].read_only = True +          return ret      def get_pk_field(self, model_field): diff --git a/rest_framework/tests/serializer.py b/rest_framework/tests/serializer.py index 8d1de429..059593a9 100644 --- a/rest_framework/tests/serializer.py +++ b/rest_framework/tests/serializer.py @@ -51,6 +51,7 @@ class PersonSerializer(serializers.ModelSerializer):      class Meta:          model = Person          fields = ('name', 'age', 'info') +        read_only_fields = ('age',)  class BasicTests(TestCase): @@ -107,7 +108,8 @@ class BasicTests(TestCase):          self.assertEquals(serializer.data['sub_comment'], 'And Merry Christmas!')      def test_model_fields_as_expected(self): -        """ Make sure that the fields returned are the same as defined +        """ +        Make sure that the fields returned are the same as defined          in the Meta data          """          serializer = PersonSerializer(self.person) @@ -115,12 +117,25 @@ class BasicTests(TestCase):                            set(['name', 'age', 'info']))      def test_field_with_dictionary(self): -        """ Make sure that dictionaries from fields are left intact +        """ +        Make sure that dictionaries from fields are left intact          """          serializer = PersonSerializer(self.person)          expected = self.person_data          self.assertEquals(serializer.data['info'], expected) +    def test_read_only_fields(self): +        """ +        Attempting to update fields set as read_only should have no effect. +        """ + +        serializer = PersonSerializer(self.person, data={'name': 'dwight', 'age': 99}) +        self.assertEquals(serializer.is_valid(), True) +        instance = serializer.save() +        self.assertEquals(serializer.errors, {}) +        # Assert age is unchanged (35) +        self.assertEquals(instance.age, self.person_data['age']) +  class ValidationTests(TestCase):      def setUp(self):  | 
