Allow serializers to handle dicts as well as objects. Fixes #447.

This commit is contained in:
Tom Christie 2013-02-07 12:57:40 +00:00
parent 8113d66126
commit 670ac25b25
4 changed files with 48 additions and 7 deletions

View File

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

View File

@ -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):

View File

@ -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]

View File

@ -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(