aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJamie Matthews2012-10-22 15:12:25 +0100
committerJamie Matthews2012-10-22 15:12:25 +0100
commit45d4622f090f8d81a04b4d3e888017419676bbc0 (patch)
treebe8123972b230c118709a70cda0dd746c91645e2
parentd53ee8a10c5fd3c95a577a409d39a394a838b0b7 (diff)
downloaddjango-rest-framework-45d4622f090f8d81a04b4d3e888017419676bbc0.tar.bz2
Fix serialization of reverse relationships
-rw-r--r--rest_framework/serializers.py23
-rw-r--r--rest_framework/tests/models.py11
-rw-r--r--rest_framework/tests/serializer.py29
3 files changed, 53 insertions, 10 deletions
diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py
index 6724bbdf..221cbf2f 100644
--- a/rest_framework/serializers.py
+++ b/rest_framework/serializers.py
@@ -247,6 +247,19 @@ class BaseSerializer(Field):
if not self._errors:
return self.restore_object(attrs, instance=getattr(self, 'object', None))
+ def field_to_native(self, obj, field_name):
+ """
+ Override default so that we can apply ModelSerializer as a nested
+ field to relationships.
+ """
+ obj = getattr(obj, self.source or field_name)
+
+ # If the object has an "all" method, assume it's a relationship
+ if is_simple_callable(getattr(obj, 'all', None)):
+ return [self.to_native(item) for item in obj.all()]
+
+ return self.to_native(obj)
+
@property
def errors(self):
"""
@@ -295,16 +308,6 @@ class ModelSerializer(Serializer):
"""
_options_class = ModelSerializerOptions
- def field_to_native(self, obj, field_name):
- """
- Override default so that we can apply ModelSerializer as a nested
- field to relationships.
- """
- obj = getattr(obj, self.source or field_name)
- if obj.__class__.__name__ in ('RelatedManager', 'ManyRelatedManager'):
- return [self.to_native(item) for item in obj.all()]
- return self.to_native(obj)
-
def default_fields(self, serialize, obj=None, data=None, nested=False):
"""
Return all the fields that should be serialized for the model.
diff --git a/rest_framework/tests/models.py b/rest_framework/tests/models.py
index 75dab2f7..8e721737 100644
--- a/rest_framework/tests/models.py
+++ b/rest_framework/tests/models.py
@@ -92,6 +92,17 @@ class Comment(RESTFrameworkModel):
content = models.CharField(max_length=200)
created = models.DateTimeField(auto_now_add=True)
+
class ActionItem(RESTFrameworkModel):
title = models.CharField(max_length=200)
done = models.BooleanField(default=False)
+
+
+# Models for reverse relations
+class BlogPost(RESTFrameworkModel):
+ title = models.CharField(max_length=100)
+
+
+class BlogPostComment(RESTFrameworkModel):
+ text = models.TextField()
+ blog_post = models.ForeignKey(BlogPost)
diff --git a/rest_framework/tests/serializer.py b/rest_framework/tests/serializer.py
index bd1f07da..2dfc04e1 100644
--- a/rest_framework/tests/serializer.py
+++ b/rest_framework/tests/serializer.py
@@ -302,3 +302,32 @@ class CallableDefaultValueTests(TestCase):
self.assertEquals(len(self.objects.all()), 1)
self.assertEquals(instance.pk, 1)
self.assertEquals(instance.text, 'overridden')
+
+
+class ManyRelatedTests(TestCase):
+ def setUp(self):
+
+ class BlogPostCommentSerializer(serializers.Serializer):
+ text = serializers.CharField()
+
+ class BlogPostSerializer(serializers.Serializer):
+ title = serializers.CharField()
+ comments = BlogPostCommentSerializer(source='blogpostcomment_set')
+
+ self.serializer_class = BlogPostSerializer
+
+ def test_reverse_relations(self):
+ post = BlogPost.objects.create(title="Test blog post")
+ post.blogpostcomment_set.create(text="I hate this blog post")
+ post.blogpostcomment_set.create(text="I love this blog post")
+
+ serializer = self.serializer_class(instance=post)
+ expected = {
+ 'title': 'Test blog post',
+ 'comments': [
+ {'text': 'I hate this blog post'},
+ {'text': 'I love this blog post'}
+ ]
+ }
+
+ self.assertEqual(serializer.data, expected)