This commit is contained in:
Mark Shirley 2013-03-23 09:04:55 -07:00
commit ea5d49bbd5
2 changed files with 108 additions and 5 deletions

View File

@ -386,12 +386,15 @@ class BaseSerializer(WritableField):
'data': value, 'data': value,
'context': self.context, 'context': self.context,
'partial': self.partial, 'partial': self.partial,
'many': self.many 'many': self.many,
'allow_delete': self.allow_delete
} }
serializer = self.__class__(**kwargs) serializer = self.__class__(**kwargs)
serializer.root = self.root
if serializer.is_valid(): if serializer.is_valid():
into[self.source or field_name] = serializer.object into[self.source or field_name] = serializer.object
self.root._deleted = (self.root._deleted or []) + (serializer._deleted or [])
else: else:
# Propagate errors up to our parent # Propagate errors up to our parent
raise NestedValidationError(serializer.errors) raise NestedValidationError(serializer.errors)
@ -452,7 +455,7 @@ class BaseSerializer(WritableField):
ret.append(self.from_native(item, None)) ret.append(self.from_native(item, None))
errors.append(self._errors) errors.append(self._errors)
if update: if update and self.allow_delete:
self._deleted = identity_to_objects.values() self._deleted = identity_to_objects.values()
self._errors = any(errors) and errors or [] self._errors = any(errors) and errors or []
@ -508,7 +511,7 @@ class BaseSerializer(WritableField):
else: else:
self.save_object(self.object, **kwargs) self.save_object(self.object, **kwargs)
if self.allow_delete and self._deleted: if self._deleted:
[self.delete_object(item) for item in self._deleted] [self.delete_object(item) for item in self._deleted]
return self.object return self.object

View File

@ -138,12 +138,46 @@ class BulkUpdateSerializerTests(TestCase):
self.title = title self.title = title
self.author = author self.author = author
@property
def pages(self):
return [item for item in Page.object_map.values() if item.book_id == self.id]
def save(self): def save(self):
Book.object_map[self.id] = self Book.object_map[self.id] = self
def delete(self): def delete(self):
del Book.object_map[self.id] del Book.object_map[self.id]
class Page(object):
"""
A data type that can be persisted to a mock storage backend
with `.save()` and `.delete()`.
"""
object_map = {}
def __init__(self, id, number, book_id):
self.id = id
self.number = number
self.book_id = book_id
def save(self):
Page.object_map[self.id] = self
def delete(self):
del Page.object_map[self.id]
class PageSerializer(serializers.Serializer):
id = serializers.IntegerField()
number = serializers.IntegerField()
book_id = serializers.IntegerField()
def restore_object(self, attrs, instance=None):
if instance:
instance.id = attrs['id']
instance.number = attrs['number']
return instance
return Page(**attrs)
class BookSerializer(serializers.Serializer): class BookSerializer(serializers.Serializer):
id = serializers.IntegerField() id = serializers.IntegerField()
title = serializers.CharField(max_length=100) title = serializers.CharField(max_length=100)
@ -157,8 +191,22 @@ class BulkUpdateSerializerTests(TestCase):
return instance return instance
return Book(**attrs) return Book(**attrs)
self.Book = Book class BookNestedSerializer(serializers.Serializer):
self.BookSerializer = BookSerializer id = serializers.IntegerField()
title = serializers.CharField(max_length=100)
author = serializers.CharField(max_length=100)
pages = PageSerializer(many=True, allow_delete=True)
def restore_object(self, attrs, instance=None):
if instance:
instance.id = attrs['id']
instance.title = attrs['title']
instance.author = attrs['author']
return instance
return Book(**attrs)
self.Book, self.Page = Book, Page
self.BookSerializer, self.BookNestedSerializer = BookSerializer, BookNestedSerializer
data = [ data = [
{ {
@ -180,6 +228,29 @@ class BulkUpdateSerializerTests(TestCase):
book = Book(item['id'], item['title'], item['author']) book = Book(item['id'], item['title'], item['author'])
book.save() book.save()
data = [
{
'id': 0,
'number': 1,
'book_id': 0
},
{
'id': 1,
'number': 2,
'book_id': 0
},
{
'id': 2,
'number': 3,
'book_id': 0
}
]
for item in data:
page = Page(item['id'], item['number'], item['book_id'])
page.save()
def books(self): def books(self):
""" """
Return all the objects in the mock storage backend. Return all the objects in the mock storage backend.
@ -208,6 +279,35 @@ class BulkUpdateSerializerTests(TestCase):
new_data = self.BookSerializer(self.books(), many=True).data new_data = self.BookSerializer(self.books(), many=True).data
self.assertEqual(data, new_data) self.assertEqual(data, new_data)
def test_nested_bulk_update_success(self):
"""
Correct bulk update serialization should return the input data.
"""
data = {
'id': 0,
'title': 'The electric kool-aid acid test',
'author': 'Tom Wolfe',
'pages': [
{
'id': 0,
'number': 1,
'book_id': 0
},
{
'id': 2,
'number': 3,
'book_id': 0
}
]
}
book = self.Book.object_map[0]
serializer = self.BookNestedSerializer(book, data=data)
self.assertEqual(serializer.is_valid(), True)
serializer.save()
book = self.Book.object_map[0]
new_data = self.BookNestedSerializer(book).data
self.assertEqual(data, new_data)
def test_bulk_update_and_create(self): def test_bulk_update_and_create(self):
""" """
Bulk update serialization may also include created items. Bulk update serialization may also include created items.