mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-01-23 15:54:16 +03:00
Allow serializers to handle dicts as well as objects. Fixes #447.
This commit is contained in:
parent
8113d66126
commit
670ac25b25
|
@ -29,6 +29,7 @@ You can determine your currently installed version using `pip freeze`:
|
||||||
### Master
|
### Master
|
||||||
|
|
||||||
* Added a `post_save()` hook to the generic views.
|
* 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 styling on browsable API login.
|
||||||
* Bugfix: Fix issue with deserializing empty to-many relations.
|
* 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.
|
* Bugfix: Ensure model field validation is still applied for ModelSerializer subclasses with an custom `.restore_object()` method.
|
||||||
|
|
|
@ -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):
|
class Field(object):
|
||||||
read_only = True
|
read_only = True
|
||||||
creation_counter = 0
|
creation_counter = 0
|
||||||
|
@ -82,11 +97,9 @@ class Field(object):
|
||||||
if self.source:
|
if self.source:
|
||||||
value = obj
|
value = obj
|
||||||
for component in self.source.split('.'):
|
for component in self.source.split('.'):
|
||||||
value = getattr(value, component)
|
value = get_component(value, component)
|
||||||
if is_simple_callable(value):
|
|
||||||
value = value()
|
|
||||||
else:
|
else:
|
||||||
value = getattr(obj, field_name)
|
value = get_component(obj, field_name)
|
||||||
return self.to_native(value)
|
return self.to_native(value)
|
||||||
|
|
||||||
def to_native(self, value):
|
def to_native(self, value):
|
||||||
|
|
|
@ -325,7 +325,7 @@ class BaseSerializer(Field):
|
||||||
if self.many is not None:
|
if self.many is not None:
|
||||||
many = self.many
|
many = self.many
|
||||||
else:
|
else:
|
||||||
many = hasattr(obj, '__iter__') and not isinstance(obj, Page)
|
many = hasattr(obj, '__iter__') and not isinstance(obj, (Page, dict))
|
||||||
|
|
||||||
if many:
|
if many:
|
||||||
return [self.to_native(item) for item in obj]
|
return [self.to_native(item) for item in obj]
|
||||||
|
@ -343,7 +343,7 @@ class BaseSerializer(Field):
|
||||||
if self.many is not None:
|
if self.many is not None:
|
||||||
many = self.many
|
many = self.many
|
||||||
else:
|
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
|
# TODO: error data when deserializing lists
|
||||||
if many:
|
if many:
|
||||||
|
@ -368,7 +368,7 @@ class BaseSerializer(Field):
|
||||||
if self.many is not None:
|
if self.many is not None:
|
||||||
many = self.many
|
many = self.many
|
||||||
else:
|
else:
|
||||||
many = hasattr(obj, '__iter__') and not isinstance(obj, Page)
|
many = hasattr(obj, '__iter__') and not isinstance(obj, (Page, dict))
|
||||||
|
|
||||||
if many:
|
if many:
|
||||||
self._data = [self.to_native(item) for item in obj]
|
self._data = [self.to_native(item) for item in obj]
|
||||||
|
|
|
@ -185,6 +185,33 @@ class BasicTests(TestCase):
|
||||||
self.assertEquals(instance.age, self.person_data['age'])
|
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):
|
class ValidationTests(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.comment = Comment(
|
self.comment = Comment(
|
||||||
|
|
Loading…
Reference in New Issue
Block a user