aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTom Christie2013-02-07 12:57:40 +0000
committerTom Christie2013-02-07 12:57:40 +0000
commit670ac25b25a3c7fb54fca6aa9344b8250ab49edb (patch)
treefdd12baeb96f10d8824d172553dbd6e469e8798d
parent8113d661260834a91d91481f31860398cde9212d (diff)
downloaddjango-rest-framework-670ac25b25a3c7fb54fca6aa9344b8250ab49edb.tar.bz2
Allow serializers to handle dicts as well as objects. Fixes #447.
-rw-r--r--docs/topics/release-notes.md1
-rw-r--r--rest_framework/fields.py21
-rw-r--r--rest_framework/serializers.py6
-rw-r--r--rest_framework/tests/serializer.py27
4 files changed, 48 insertions, 7 deletions
diff --git a/docs/topics/release-notes.md b/docs/topics/release-notes.md
index d5f060e7..4317b83c 100644
--- a/docs/topics/release-notes.md
+++ b/docs/topics/release-notes.md
@@ -29,6 +29,7 @@ You can determine your currently installed version using `pip freeze`:
### Master
* Added a `post_save()` hook to the generic views.
+* Allow serializers to handle dicts as well as objects.
* Bugfix: Fix styling on browsable API login.
* Bugfix: Fix issue with deserializing empty to-many relations.
* Bugfix: Ensure model field validation is still applied for ModelSerializer subclasses with an custom `.restore_object()` method.
diff --git a/rest_framework/fields.py b/rest_framework/fields.py
index 2c3e59b5..aa6fa3ab 100644
--- a/rest_framework/fields.py
+++ b/rest_framework/fields.py
@@ -30,6 +30,21 @@ def is_simple_callable(obj):
)
+def get_component(obj, attr_name):
+ """
+ Given an object, and an attribute name,
+ return that attribute on the object.
+ """
+ if isinstance(obj, dict):
+ val = obj[attr_name]
+ else:
+ val = getattr(obj, attr_name)
+
+ if is_simple_callable(val):
+ return val()
+ return val
+
+
class Field(object):
read_only = True
creation_counter = 0
@@ -82,11 +97,9 @@ class Field(object):
if self.source:
value = obj
for component in self.source.split('.'):
- value = getattr(value, component)
- if is_simple_callable(value):
- value = value()
+ value = get_component(value, component)
else:
- value = getattr(obj, field_name)
+ value = get_component(obj, field_name)
return self.to_native(value)
def to_native(self, value):
diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py
index 7daeac41..a6dbf5d7 100644
--- a/rest_framework/serializers.py
+++ b/rest_framework/serializers.py
@@ -325,7 +325,7 @@ class BaseSerializer(Field):
if self.many is not None:
many = self.many
else:
- many = hasattr(obj, '__iter__') and not isinstance(obj, Page)
+ many = hasattr(obj, '__iter__') and not isinstance(obj, (Page, dict))
if many:
return [self.to_native(item) for item in obj]
@@ -343,7 +343,7 @@ class BaseSerializer(Field):
if self.many is not None:
many = self.many
else:
- many = hasattr(data, '__iter__') and not isinstance(data, dict)
+ many = hasattr(data, '__iter__') and not isinstance(data, (Page, dict))
# TODO: error data when deserializing lists
if many:
@@ -368,7 +368,7 @@ class BaseSerializer(Field):
if self.many is not None:
many = self.many
else:
- many = hasattr(obj, '__iter__') and not isinstance(obj, Page)
+ many = hasattr(obj, '__iter__') and not isinstance(obj, (Page, dict))
if many:
self._data = [self.to_native(item) for item in obj]
diff --git a/rest_framework/tests/serializer.py b/rest_framework/tests/serializer.py
index 62de16ab..2d17e99d 100644
--- a/rest_framework/tests/serializer.py
+++ b/rest_framework/tests/serializer.py
@@ -185,6 +185,33 @@ class BasicTests(TestCase):
self.assertEquals(instance.age, self.person_data['age'])
+class DictStyleSerializer(serializers.Serializer):
+ """
+ Note that we don't have any `restore_object` method, so the default
+ case of simply returning a dict will apply.
+ """
+ email = serializers.EmailField()
+
+
+class DictStyleSerializerTests(TestCase):
+ def test_dict_style_deserialize(self):
+ """
+ Ensure serializers can deserialize into a dict.
+ """
+ data = {'email': 'foo@example.com'}
+ serializer = DictStyleSerializer(data=data)
+ self.assertTrue(serializer.is_valid())
+ self.assertEquals(serializer.data, data)
+
+ def test_dict_style_serialize(self):
+ """
+ Ensure serializers can serialize dict objects.
+ """
+ data = {'email': 'foo@example.com'}
+ serializer = DictStyleSerializer(data)
+ self.assertEquals(serializer.data, data)
+
+
class ValidationTests(TestCase):
def setUp(self):
self.comment = Comment(