Merge pull request #394 from tomchristie/read_only_fields

Read only fields
This commit is contained in:
Tom Christie 2012-11-09 09:04:45 -08:00
commit da1aa5542c
5 changed files with 41 additions and 5 deletions

View File

@ -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. 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 ## 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. 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.

View File

@ -32,7 +32,7 @@ REST framework requires the following:
The following packages are optional: 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. * [PyYAML][yaml] (3.10+) - YAML content-type support.
* [django-filter][django-filter] (master) - Filtering 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... Install using `pip`, including any optional packages you want...
pip install djangorestframework pip install djangorestframework
pip install markdown # Recommended if using the browseable API. pip install markdown # Markdown support for the browseable API.
pip install pyyaml # Required for yaml content-type support. 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. ...or clone the project from github.

View File

@ -4,6 +4,10 @@
> >
> &mdash; Eric S. Raymond, [The Cathedral and the Bazaar][cite]. > &mdash; Eric S. Raymond, [The Cathedral and the Bazaar][cite].
## Master
* Support for `read_only_fields` on `ModelSerializer` classes.
## 2.1.2 ## 2.1.2
**Date**: 9th Nov 2012 **Date**: 9th Nov 2012

View File

@ -321,6 +321,7 @@ class ModelSerializerOptions(SerializerOptions):
def __init__(self, meta): def __init__(self, meta):
super(ModelSerializerOptions, self).__init__(meta) super(ModelSerializerOptions, self).__init__(meta)
self.model = getattr(meta, 'model', None) self.model = getattr(meta, 'model', None)
self.read_only_fields = getattr(meta, 'read_only_fields', ())
class ModelSerializer(Serializer): class ModelSerializer(Serializer):
@ -369,6 +370,12 @@ class ModelSerializer(Serializer):
field.initialize(parent=self, field_name=model_field.name) field.initialize(parent=self, field_name=model_field.name)
ret[model_field.name] = field 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 return ret
def get_pk_field(self, model_field): def get_pk_field(self, model_field):

View File

@ -51,6 +51,7 @@ class PersonSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = Person model = Person
fields = ('name', 'age', 'info') fields = ('name', 'age', 'info')
read_only_fields = ('age',)
class BasicTests(TestCase): class BasicTests(TestCase):
@ -107,7 +108,8 @@ class BasicTests(TestCase):
self.assertEquals(serializer.data['sub_comment'], 'And Merry Christmas!') self.assertEquals(serializer.data['sub_comment'], 'And Merry Christmas!')
def test_model_fields_as_expected(self): 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 in the Meta data
""" """
serializer = PersonSerializer(self.person) serializer = PersonSerializer(self.person)
@ -115,12 +117,25 @@ class BasicTests(TestCase):
set(['name', 'age', 'info'])) set(['name', 'age', 'info']))
def test_field_with_dictionary(self): 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) serializer = PersonSerializer(self.person)
expected = self.person_data expected = self.person_data
self.assertEquals(serializer.data['info'], expected) 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): class ValidationTests(TestCase):
def setUp(self): def setUp(self):