Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
D
django-rest-framework
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
django-rest-framework
Commits
ed541864
Commit
ed541864
authored
Nov 06, 2014
by
Tom Christie
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Support for bulk create. Closes #1965.
parent
73daf407
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
176 additions
and
133 deletions
+176
-133
rest_framework/fields.py
+1
-1
rest_framework/serializers.py
+54
-11
tests/test_fields.py
+1
-1
tests/test_serializer_bulk_update.py
+120
-120
No files found.
rest_framework/fields.py
View file @
ed541864
...
@@ -943,7 +943,7 @@ class ChoiceField(Field):
...
@@ -943,7 +943,7 @@ class ChoiceField(Field):
class
MultipleChoiceField
(
ChoiceField
):
class
MultipleChoiceField
(
ChoiceField
):
default_error_messages
=
{
default_error_messages
=
{
'invalid_choice'
:
_
(
'`{input}` is not a valid choice.'
),
'invalid_choice'
:
_
(
'`{input}` is not a valid choice.'
),
'not_a_list'
:
_
(
'Expected a list of items but got type `{input_type}`'
)
'not_a_list'
:
_
(
'Expected a list of items but got type `{input_type}`
.
'
)
}
}
default_empty_html
=
[]
default_empty_html
=
[]
...
...
rest_framework/serializers.py
View file @
ed541864
...
@@ -90,12 +90,10 @@ class BaseSerializer(Field):
...
@@ -90,12 +90,10 @@ class BaseSerializer(Field):
raise
NotImplementedError
(
'`create()` must be implemented.'
)
raise
NotImplementedError
(
'`create()` must be implemented.'
)
def
save
(
self
,
**
kwargs
):
def
save
(
self
,
**
kwargs
):
validated_data
=
self
.
validated_data
validated_data
=
dict
(
if
kwargs
:
list
(
self
.
validated_data
.
items
())
+
validated_data
=
dict
(
list
(
kwargs
.
items
())
list
(
validated_data
.
items
())
+
)
list
(
kwargs
.
items
())
)
if
self
.
instance
is
not
None
:
if
self
.
instance
is
not
None
:
self
.
instance
=
self
.
update
(
self
.
instance
,
validated_data
)
self
.
instance
=
self
.
update
(
self
.
instance
,
validated_data
)
...
@@ -210,9 +208,9 @@ class BoundField(object):
...
@@ -210,9 +208,9 @@ class BoundField(object):
class
NestedBoundField
(
BoundField
):
class
NestedBoundField
(
BoundField
):
"""
"""
This
BoundField
additionally implements __iter__ and __getitem__
This
`BoundField`
additionally implements __iter__ and __getitem__
in order to support nested bound fields. This class is the type of
in order to support nested bound fields. This class is the type of
BoundField
that is used for serializer fields.
`BoundField`
that is used for serializer fields.
"""
"""
def
__iter__
(
self
):
def
__iter__
(
self
):
for
field
in
self
.
fields
.
values
():
for
field
in
self
.
fields
.
values
():
...
@@ -460,6 +458,10 @@ class ListSerializer(BaseSerializer):
...
@@ -460,6 +458,10 @@ class ListSerializer(BaseSerializer):
child
=
None
child
=
None
many
=
True
many
=
True
default_error_messages
=
{
'not_a_list'
:
_
(
'Expected a list of items but got type `{input_type}`.'
)
}
def
__init__
(
self
,
*
args
,
**
kwargs
):
def
__init__
(
self
,
*
args
,
**
kwargs
):
self
.
child
=
kwargs
.
pop
(
'child'
,
copy
.
deepcopy
(
self
.
child
))
self
.
child
=
kwargs
.
pop
(
'child'
,
copy
.
deepcopy
(
self
.
child
))
assert
self
.
child
is
not
None
,
'`child` is a required argument.'
assert
self
.
child
is
not
None
,
'`child` is a required argument.'
...
@@ -485,7 +487,31 @@ class ListSerializer(BaseSerializer):
...
@@ -485,7 +487,31 @@ class ListSerializer(BaseSerializer):
"""
"""
if
html
.
is_html_input
(
data
):
if
html
.
is_html_input
(
data
):
data
=
html
.
parse_html_list
(
data
)
data
=
html
.
parse_html_list
(
data
)
return
[
self
.
child
.
run_validation
(
item
)
for
item
in
data
]
if
not
isinstance
(
data
,
list
):
message
=
self
.
error_messages
[
'not_a_list'
]
.
format
(
input_type
=
type
(
data
)
.
__name__
)
raise
ValidationError
({
api_settings
.
NON_FIELD_ERRORS_KEY
:
[
message
]
})
ret
=
[]
errors
=
ReturnList
(
serializer
=
self
)
for
item
in
data
:
try
:
validated
=
self
.
child
.
run_validation
(
item
)
except
ValidationError
,
exc
:
errors
.
append
(
exc
.
detail
)
else
:
ret
.
append
(
validated
)
errors
.
append
({})
if
any
(
errors
):
raise
ValidationError
(
errors
)
return
ret
def
to_representation
(
self
,
data
):
def
to_representation
(
self
,
data
):
"""
"""
...
@@ -497,8 +523,25 @@ class ListSerializer(BaseSerializer):
...
@@ -497,8 +523,25 @@ class ListSerializer(BaseSerializer):
serializer
=
self
serializer
=
self
)
)
def
create
(
self
,
attrs_list
):
def
save
(
self
,
**
kwargs
):
return
[
self
.
child
.
create
(
attrs
)
for
attrs
in
attrs_list
]
assert
self
.
instance
is
None
,
(
"Serializers do not support multiple update by default, because "
"it would be unclear how to deal with insertions, updates and "
"deletions. If you need to support multiple update, use a "
"`ListSerializer` class and override `.save()` so you can specify "
"the behavior exactly."
)
validated_data
=
[
dict
(
list
(
attrs
.
items
())
+
list
(
kwargs
.
items
()))
for
attrs
in
self
.
validated_data
]
self
.
instance
=
[
self
.
child
.
create
(
attrs
)
for
attrs
in
validated_data
]
return
self
.
instance
def
__repr__
(
self
):
def
__repr__
(
self
):
return
representation
.
list_repr
(
self
,
indent
=
1
)
return
representation
.
list_repr
(
self
,
indent
=
1
)
...
...
tests/test_fields.py
View file @
ed541864
...
@@ -859,7 +859,7 @@ class TestMultipleChoiceField(FieldValues):
...
@@ -859,7 +859,7 @@ class TestMultipleChoiceField(FieldValues):
(
'aircon'
,
'manual'
):
set
([
'aircon'
,
'manual'
]),
(
'aircon'
,
'manual'
):
set
([
'aircon'
,
'manual'
]),
}
}
invalid_inputs
=
{
invalid_inputs
=
{
'abc'
:
[
'Expected a list of items but got type `str`'
],
'abc'
:
[
'Expected a list of items but got type `str`
.
'
],
(
'aircon'
,
'incorrect'
):
[
'`incorrect` is not a valid choice.'
]
(
'aircon'
,
'incorrect'
):
[
'`incorrect` is not a valid choice.'
]
}
}
outputs
=
[
outputs
=
[
...
...
tests/test_serializer_bulk_update.py
View file @
ed541864
#
"""
"""
#
Tests to cover bulk create and update using serializers.
Tests to cover bulk create and update using serializers.
#
"""
"""
#
from __future__ import unicode_literals
from
__future__
import
unicode_literals
#
from django.test import TestCase
from
django.test
import
TestCase
#
from rest_framework import serializers
from
rest_framework
import
serializers
#
class BulkCreateSerializerTests(TestCase):
class
BulkCreateSerializerTests
(
TestCase
):
#
"""
"""
#
Creating multiple instances using serializers.
Creating multiple instances using serializers.
#
"""
"""
#
def setUp(self):
def
setUp
(
self
):
#
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
)
#
author = serializers.CharField(max_length=100)
author
=
serializers
.
CharField
(
max_length
=
100
)
#
self.BookSerializer = BookSerializer
self
.
BookSerializer
=
BookSerializer
#
def test_bulk_create_success(self):
def
test_bulk_create_success
(
self
):
#
"""
"""
#
Correct bulk update serialization should return the input data.
Correct bulk update serialization should return the input data.
#
"""
"""
#
data = [
data
=
[
#
{
{
#
'id': 0,
'id'
:
0
,
#
'title': 'The electric kool-aid acid test',
'title'
:
'The electric kool-aid acid test'
,
#
'author': 'Tom Wolfe'
'author'
:
'Tom Wolfe'
#
}, {
},
{
#
'id': 1,
'id'
:
1
,
#
'title': 'If this is a man',
'title'
:
'If this is a man'
,
#
'author': 'Primo Levi'
'author'
:
'Primo Levi'
#
}, {
},
{
#
'id': 2,
'id'
:
2
,
#
'title': 'The wind-up bird chronicle',
'title'
:
'The wind-up bird chronicle'
,
#
'author': 'Haruki Murakami'
'author'
:
'Haruki Murakami'
#
}
}
#
]
]
#
serializer = self.BookSerializer(data=data, many=True)
serializer
=
self
.
BookSerializer
(
data
=
data
,
many
=
True
)
#
self.assertEqual(serializer.is_valid(), True)
self
.
assertEqual
(
serializer
.
is_valid
(),
True
)
# self.assertEqual(serializer.object
, data)
self
.
assertEqual
(
serializer
.
validated_data
,
data
)
#
def test_bulk_create_errors(self):
def
test_bulk_create_errors
(
self
):
#
"""
"""
# Correct bulk update serialization should return the input data
.
Incorrect bulk create serialization should return errors
.
#
"""
"""
#
data = [
data
=
[
#
{
{
#
'id': 0,
'id'
:
0
,
#
'title': 'The electric kool-aid acid test',
'title'
:
'The electric kool-aid acid test'
,
#
'author': 'Tom Wolfe'
'author'
:
'Tom Wolfe'
#
}, {
},
{
#
'id': 1,
'id'
:
1
,
#
'title': 'If this is a man',
'title'
:
'If this is a man'
,
#
'author': 'Primo Levi'
'author'
:
'Primo Levi'
#
}, {
},
{
#
'id': 'foo',
'id'
:
'foo'
,
#
'title': 'The wind-up bird chronicle',
'title'
:
'The wind-up bird chronicle'
,
#
'author': 'Haruki Murakami'
'author'
:
'Haruki Murakami'
#
}
}
#
]
]
#
expected_errors = [
expected_errors
=
[
#
{},
{},
#
{},
{},
# {'id': ['Enter a whole number
.']}
{
'id'
:
[
'A valid integer is required
.'
]}
#
]
]
#
serializer = self.BookSerializer(data=data, many=True)
serializer
=
self
.
BookSerializer
(
data
=
data
,
many
=
True
)
#
self.assertEqual(serializer.is_valid(), False)
self
.
assertEqual
(
serializer
.
is_valid
(),
False
)
#
self.assertEqual(serializer.errors, expected_errors)
self
.
assertEqual
(
serializer
.
errors
,
expected_errors
)
#
def test_invalid_list_datatype(self):
def
test_invalid_list_datatype
(
self
):
#
"""
"""
#
Data containing list of incorrect data type should return errors.
Data containing list of incorrect data type should return errors.
#
"""
"""
#
data = ['foo', 'bar', 'baz']
data
=
[
'foo'
,
'bar'
,
'baz'
]
#
serializer = self.BookSerializer(data=data, many=True)
serializer
=
self
.
BookSerializer
(
data
=
data
,
many
=
True
)
#
self.assertEqual(serializer.is_valid(), False)
self
.
assertEqual
(
serializer
.
is_valid
(),
False
)
#
expected_errors = [
expected_errors
=
[
# {'non_field_errors': ['Invalid data
']},
{
'non_field_errors'
:
[
'Invalid data. Expected a dictionary, but got unicode.
'
]},
# {'non_field_errors': ['Invalid data
']},
{
'non_field_errors'
:
[
'Invalid data. Expected a dictionary, but got unicode.
'
]},
# {'non_field_errors': ['Invalid data
']}
{
'non_field_errors'
:
[
'Invalid data. Expected a dictionary, but got unicode.
'
]}
#
]
]
#
self.assertEqual(serializer.errors, expected_errors)
self
.
assertEqual
(
serializer
.
errors
,
expected_errors
)
#
def test_invalid_single_datatype(self):
def
test_invalid_single_datatype
(
self
):
#
"""
"""
#
Data containing a single incorrect data type should return errors.
Data containing a single incorrect data type should return errors.
#
"""
"""
#
data = 123
data
=
123
#
serializer = self.BookSerializer(data=data, many=True)
serializer
=
self
.
BookSerializer
(
data
=
data
,
many
=
True
)
#
self.assertEqual(serializer.is_valid(), False)
self
.
assertEqual
(
serializer
.
is_valid
(),
False
)
# expected_errors = {'non_field_errors': ['Expected a list of items
.']}
expected_errors
=
{
'non_field_errors'
:
[
'Expected a list of items but got type `int`
.'
]}
#
self.assertEqual(serializer.errors, expected_errors)
self
.
assertEqual
(
serializer
.
errors
,
expected_errors
)
#
def test_invalid_single_object(self):
def
test_invalid_single_object
(
self
):
#
"""
"""
#
Data containing only a single object, instead of a list of objects
Data containing only a single object, instead of a list of objects
#
should return errors.
should return errors.
#
"""
"""
#
data = {
data
=
{
#
'id': 0,
'id'
:
0
,
#
'title': 'The electric kool-aid acid test',
'title'
:
'The electric kool-aid acid test'
,
#
'author': 'Tom Wolfe'
'author'
:
'Tom Wolfe'
#
}
}
#
serializer = self.BookSerializer(data=data, many=True)
serializer
=
self
.
BookSerializer
(
data
=
data
,
many
=
True
)
#
self.assertEqual(serializer.is_valid(), False)
self
.
assertEqual
(
serializer
.
is_valid
(),
False
)
# expected_errors = {'non_field_errors': ['Expected a list of items
.']}
expected_errors
=
{
'non_field_errors'
:
[
'Expected a list of items but got type `dict`
.'
]}
#
self.assertEqual(serializer.errors, expected_errors)
self
.
assertEqual
(
serializer
.
errors
,
expected_errors
)
# class BulkUpdateSerializerTests(TestCase):
# class BulkUpdateSerializerTests(TestCase):
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment