ManyPrimaryKeyRelatedField now supports create for one-to-many rel

This commit is contained in:
toran billups 2012-12-15 20:55:36 -06:00
parent 1d24d1fc59
commit 008dafce17
3 changed files with 96 additions and 0 deletions

View File

@ -496,12 +496,19 @@ class ModelSerializer(Serializer):
Restore the model instance. Restore the model instance.
""" """
self.m2m_data = {} self.m2m_data = {}
self.related_data = {}
if instance is not None: if instance is not None:
for key, val in attrs.items(): for key, val in attrs.items():
setattr(instance, key, val) setattr(instance, key, val)
return instance return instance
# Related relations
for (obj, model) in self.opts.model._meta.get_all_related_objects_with_model():
field_name = obj.field.related_query_name()
if field_name in attrs:
self.related_data[field_name] = attrs.pop(field_name)
# Reverse relations # Reverse relations
for (obj, model) in self.opts.model._meta.get_all_related_m2m_objects_with_model(): for (obj, model) in self.opts.model._meta.get_all_related_m2m_objects_with_model():
field_name = obj.field.related_query_name() field_name = obj.field.related_query_name()
@ -532,6 +539,11 @@ class ModelSerializer(Serializer):
setattr(self.object, accessor_name, object_list) setattr(self.object, accessor_name, object_list)
self.m2m_data = {} self.m2m_data = {}
if getattr(self, 'related_data', None):
for accessor_name, object_list in self.related_data.items():
setattr(self.object, accessor_name, object_list)
self.related_data = {}
return self.object return self.object

View File

@ -149,6 +149,11 @@ class BlogPostComment(RESTFrameworkModel):
blog_post = models.ForeignKey(BlogPost) blog_post = models.ForeignKey(BlogPost)
class BlogPostRelatedComment(RESTFrameworkModel):
text = models.TextField()
blog_post = models.ForeignKey(BlogPost, related_name="comments")
class Album(RESTFrameworkModel): class Album(RESTFrameworkModel):
title = models.CharField(max_length=100, unique=True) title = models.CharField(max_length=100, unique=True)

View File

@ -816,3 +816,82 @@ class NestedSerializerContextTests(TestCase):
# This will raise RuntimeError if context doesn't get passed correctly to the nested Serializers # This will raise RuntimeError if context doesn't get passed correctly to the nested Serializers
AlbumCollectionSerializer(album_collection, context={'context_item': 'album context'}).data AlbumCollectionSerializer(album_collection, context={'context_item': 'album context'}).data
class ManyPrimaryKeyRelatedCreateTest(TestCase):
def test_create_is_valid_with_title_and_empty_comments_list(self):
data = {'title': 'foobar', 'comments': []}
serializer = self.build_model_serializer(data)
self.assertEquals(serializer.is_valid(), True)
def test_create_is_valid_with_title_and_comment(self):
data = {'title': 'foobar', 'comments': [self.comment.pk]}
serializer = self.build_model_serializer(data)
self.assertEquals(serializer.is_valid(), True)
def test_create_is_not_valid_when_title_is_empty_string(self):
data = {'title': '', 'comments': [self.comment.pk]}
serializer = self.build_model_serializer(data)
self.assertEquals(serializer.is_valid(), False)
self.assertEquals(serializer.errors, {'title': [u'This field is required.']})
def test_create_is_not_valid_when_title_present_but_no_comments(self):
data = {'title': 'foobar'}
serializer = self.build_model_serializer(data)
try:
self.assertEquals(serializer.is_valid(), False)
except TypeError as e:
self.assertEqual(e.message, "'NoneType' object is not iterable")
def test_create_without_comment_returns_expected_json_result(self):
data = {'title': 'foobar', 'comments': []}
serializer = self.build_model_serializer(data)
self.assertEquals(serializer.is_valid(), True)
instance = serializer.save()
expected = {
'title': u'foobar',
'comments': []
}
self.assertEqual(serializer.data, expected)
def test_create_with_comment_returns_expected_json_result(self):
data = {'title': 'foobar', 'comments': [self.comment.pk]}
serializer = self.build_model_serializer(data)
self.assertEquals(serializer.is_valid(), True)
instance = serializer.save()
expected = {
'title': u'foobar',
'comments': [self.comment.pk]
}
self.assertEqual(serializer.data, expected)
@property
def comment(self):
if not hasattr(self, '_comment'):
from rest_framework.tests.models import BlogPostRelatedComment
self._comment = BlogPostRelatedComment.objects.create(text="I love this blog post", blog_post=self.post)
return self._comment
@property
def post(self):
if not hasattr(self, '_post'):
from rest_framework.tests.models import BlogPost
self._post = BlogPost.objects.create(title="Test blog post")
return self._post
def build_model_serializer(self, data):
from rest_framework.tests.models import BlogPost, BlogPostRelatedComment
class BlogPostRelatedCommentSerializer(serializers.ModelSerializer):
class Meta:
model = BlogPostRelatedComment
fields = ("text")
class BlogPostSerializer(serializers.ModelSerializer):
comments = serializers.ManyPrimaryKeyRelatedField()
class Meta:
model = BlogPost
fields = ("title", "comments")
return BlogPostSerializer(data=data)