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
264d4234
Commit
264d4234
authored
Jul 16, 2015
by
Tom Christie
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added allow_empty flag for ListField, ListSerializer, ManyRelation, MultipleChoiceField.
parent
81709a2c
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
69 additions
and
6 deletions
+69
-6
rest_framework/fields.py
+13
-2
rest_framework/relations.py
+11
-1
rest_framework/serializers.py
+10
-2
tests/test_fields.py
+35
-1
No files found.
rest_framework/fields.py
View file @
264d4234
...
@@ -1141,10 +1141,15 @@ class ChoiceField(Field):
...
@@ -1141,10 +1141,15 @@ 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}".'
),
'empty'
:
_
(
'This selection may not be empty.'
)
}
}
default_empty_html
=
[]
default_empty_html
=
[]
def
__init__
(
self
,
*
args
,
**
kwargs
):
self
.
allow_empty
=
kwargs
.
pop
(
'allow_empty'
,
True
)
super
(
MultipleChoiceField
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
def
get_value
(
self
,
dictionary
):
def
get_value
(
self
,
dictionary
):
# We override the default field access in order to support
# We override the default field access in order to support
# lists in HTML forms.
# lists in HTML forms.
...
@@ -1159,6 +1164,8 @@ class MultipleChoiceField(ChoiceField):
...
@@ -1159,6 +1164,8 @@ class MultipleChoiceField(ChoiceField):
def
to_internal_value
(
self
,
data
):
def
to_internal_value
(
self
,
data
):
if
isinstance
(
data
,
type
(
''
))
or
not
hasattr
(
data
,
'__iter__'
):
if
isinstance
(
data
,
type
(
''
))
or
not
hasattr
(
data
,
'__iter__'
):
self
.
fail
(
'not_a_list'
,
input_type
=
type
(
data
)
.
__name__
)
self
.
fail
(
'not_a_list'
,
input_type
=
type
(
data
)
.
__name__
)
if
not
self
.
allow_empty
and
len
(
data
)
==
0
:
self
.
fail
(
'empty'
)
return
set
([
return
set
([
super
(
MultipleChoiceField
,
self
)
.
to_internal_value
(
item
)
super
(
MultipleChoiceField
,
self
)
.
to_internal_value
(
item
)
...
@@ -1263,11 +1270,13 @@ class ListField(Field):
...
@@ -1263,11 +1270,13 @@ class ListField(Field):
child
=
_UnvalidatedField
()
child
=
_UnvalidatedField
()
initial
=
[]
initial
=
[]
default_error_messages
=
{
default_error_messages
=
{
'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}".'
),
'empty'
:
_
(
'This list may not be empty.'
)
}
}
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
))
self
.
allow_empty
=
kwargs
.
pop
(
'allow_empty'
,
True
)
assert
not
inspect
.
isclass
(
self
.
child
),
'`child` has not been instantiated.'
assert
not
inspect
.
isclass
(
self
.
child
),
'`child` has not been instantiated.'
super
(
ListField
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
super
(
ListField
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
self
.
child
.
bind
(
field_name
=
''
,
parent
=
self
)
self
.
child
.
bind
(
field_name
=
''
,
parent
=
self
)
...
@@ -1287,6 +1296,8 @@ class ListField(Field):
...
@@ -1287,6 +1296,8 @@ class ListField(Field):
data
=
html
.
parse_html_list
(
data
)
data
=
html
.
parse_html_list
(
data
)
if
isinstance
(
data
,
type
(
''
))
or
not
hasattr
(
data
,
'__iter__'
):
if
isinstance
(
data
,
type
(
''
))
or
not
hasattr
(
data
,
'__iter__'
):
self
.
fail
(
'not_a_list'
,
input_type
=
type
(
data
)
.
__name__
)
self
.
fail
(
'not_a_list'
,
input_type
=
type
(
data
)
.
__name__
)
if
not
self
.
allow_empty
and
len
(
data
)
==
0
:
self
.
fail
(
'empty'
)
return
[
self
.
child
.
run_validation
(
item
)
for
item
in
data
]
return
[
self
.
child
.
run_validation
(
item
)
for
item
in
data
]
def
to_representation
(
self
,
data
):
def
to_representation
(
self
,
data
):
...
...
rest_framework/relations.py
View file @
264d4234
...
@@ -32,7 +32,7 @@ class PKOnlyObject(object):
...
@@ -32,7 +32,7 @@ class PKOnlyObject(object):
# rather than the parent serializer.
# rather than the parent serializer.
MANY_RELATION_KWARGS
=
(
MANY_RELATION_KWARGS
=
(
'read_only'
,
'write_only'
,
'required'
,
'default'
,
'initial'
,
'source'
,
'read_only'
,
'write_only'
,
'required'
,
'default'
,
'initial'
,
'source'
,
'label'
,
'help_text'
,
'style'
,
'error_messages'
'label'
,
'help_text'
,
'style'
,
'error_messages'
,
'allow_empty'
)
)
...
@@ -366,9 +366,14 @@ class ManyRelatedField(Field):
...
@@ -366,9 +366,14 @@ class ManyRelatedField(Field):
"""
"""
initial
=
[]
initial
=
[]
default_empty_html
=
[]
default_empty_html
=
[]
default_error_messages
=
{
'not_a_list'
:
_
(
'Expected a list of items but got type "{input_type}".'
),
'empty'
:
_
(
'This list may not be empty.'
)
}
def
__init__
(
self
,
child_relation
=
None
,
*
args
,
**
kwargs
):
def
__init__
(
self
,
child_relation
=
None
,
*
args
,
**
kwargs
):
self
.
child_relation
=
child_relation
self
.
child_relation
=
child_relation
self
.
allow_empty
=
kwargs
.
pop
(
'allow_empty'
,
True
)
assert
child_relation
is
not
None
,
'`child_relation` is a required argument.'
assert
child_relation
is
not
None
,
'`child_relation` is a required argument.'
super
(
ManyRelatedField
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
super
(
ManyRelatedField
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
self
.
child_relation
.
bind
(
field_name
=
''
,
parent
=
self
)
self
.
child_relation
.
bind
(
field_name
=
''
,
parent
=
self
)
...
@@ -386,6 +391,11 @@ class ManyRelatedField(Field):
...
@@ -386,6 +391,11 @@ class ManyRelatedField(Field):
return
dictionary
.
get
(
self
.
field_name
,
empty
)
return
dictionary
.
get
(
self
.
field_name
,
empty
)
def
to_internal_value
(
self
,
data
):
def
to_internal_value
(
self
,
data
):
if
isinstance
(
data
,
type
(
''
))
or
not
hasattr
(
data
,
'__iter__'
):
self
.
fail
(
'not_a_list'
,
input_type
=
type
(
data
)
.
__name__
)
if
not
self
.
allow_empty
and
len
(
data
)
==
0
:
self
.
fail
(
'empty'
)
return
[
return
[
self
.
child_relation
.
to_internal_value
(
item
)
self
.
child_relation
.
to_internal_value
(
item
)
for
item
in
data
for
item
in
data
...
...
rest_framework/serializers.py
View file @
264d4234
...
@@ -49,7 +49,7 @@ from rest_framework.relations import * # NOQA # isort:skip
...
@@ -49,7 +49,7 @@ from rest_framework.relations import * # NOQA # isort:skip
# rather than the parent serializer.
# rather than the parent serializer.
LIST_SERIALIZER_KWARGS
=
(
LIST_SERIALIZER_KWARGS
=
(
'read_only'
,
'write_only'
,
'required'
,
'default'
,
'initial'
,
'source'
,
'read_only'
,
'write_only'
,
'required'
,
'default'
,
'initial'
,
'source'
,
'label'
,
'help_text'
,
'style'
,
'error_messages'
,
'label'
,
'help_text'
,
'style'
,
'error_messages'
,
'allow_empty'
,
'instance'
,
'data'
,
'partial'
,
'context'
'instance'
,
'data'
,
'partial'
,
'context'
)
)
...
@@ -493,11 +493,13 @@ class ListSerializer(BaseSerializer):
...
@@ -493,11 +493,13 @@ class ListSerializer(BaseSerializer):
many
=
True
many
=
True
default_error_messages
=
{
default_error_messages
=
{
'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}".'
),
'empty'
:
_
(
'This list may not be empty.'
)
}
}
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
))
self
.
allow_empty
=
kwargs
.
pop
(
'allow_empty'
,
True
)
assert
self
.
child
is
not
None
,
'`child` is a required argument.'
assert
self
.
child
is
not
None
,
'`child` is a required argument.'
assert
not
inspect
.
isclass
(
self
.
child
),
'`child` has not been instantiated.'
assert
not
inspect
.
isclass
(
self
.
child
),
'`child` has not been instantiated.'
super
(
ListSerializer
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
super
(
ListSerializer
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
...
@@ -553,6 +555,12 @@ class ListSerializer(BaseSerializer):
...
@@ -553,6 +555,12 @@ class ListSerializer(BaseSerializer):
api_settings
.
NON_FIELD_ERRORS_KEY
:
[
message
]
api_settings
.
NON_FIELD_ERRORS_KEY
:
[
message
]
})
})
if
not
self
.
allow_empty
and
len
(
data
)
==
0
:
message
=
self
.
error_messages
[
'empty'
]
raise
ValidationError
({
api_settings
.
NON_FIELD_ERRORS_KEY
:
[
message
]
})
ret
=
[]
ret
=
[]
errors
=
[]
errors
=
[]
...
...
tests/test_fields.py
View file @
264d4234
...
@@ -1140,6 +1140,27 @@ class TestMultipleChoiceField(FieldValues):
...
@@ -1140,6 +1140,27 @@ class TestMultipleChoiceField(FieldValues):
assert
field
.
get_value
(
QueryDict
({}))
==
rest_framework
.
fields
.
empty
assert
field
.
get_value
(
QueryDict
({}))
==
rest_framework
.
fields
.
empty
class
TestEmptyMultipleChoiceField
(
FieldValues
):
"""
Invalid values for `MultipleChoiceField(allow_empty=False)`.
"""
valid_inputs
=
{
}
invalid_inputs
=
(
([],
[
'This selection may not be empty.'
]),
)
outputs
=
[
]
field
=
serializers
.
MultipleChoiceField
(
choices
=
[
(
'consistency'
,
'Consistency'
),
(
'availability'
,
'Availability'
),
(
'partition'
,
'Partition tolerance'
),
],
allow_empty
=
False
)
# File serializers...
# File serializers...
class
MockFile
:
class
MockFile
:
...
@@ -1233,7 +1254,8 @@ class TestListField(FieldValues):
...
@@ -1233,7 +1254,8 @@ class TestListField(FieldValues):
"""
"""
valid_inputs
=
[
valid_inputs
=
[
([
1
,
2
,
3
],
[
1
,
2
,
3
]),
([
1
,
2
,
3
],
[
1
,
2
,
3
]),
([
'1'
,
'2'
,
'3'
],
[
1
,
2
,
3
])
([
'1'
,
'2'
,
'3'
],
[
1
,
2
,
3
]),
([],
[])
]
]
invalid_inputs
=
[
invalid_inputs
=
[
(
'not a list'
,
[
'Expected a list of items but got type "str".'
]),
(
'not a list'
,
[
'Expected a list of items but got type "str".'
]),
...
@@ -1246,6 +1268,18 @@ class TestListField(FieldValues):
...
@@ -1246,6 +1268,18 @@ class TestListField(FieldValues):
field
=
serializers
.
ListField
(
child
=
serializers
.
IntegerField
())
field
=
serializers
.
ListField
(
child
=
serializers
.
IntegerField
())
class
TestEmptyListField
(
FieldValues
):
"""
Values for `ListField` with allow_empty=False flag.
"""
valid_inputs
=
{}
invalid_inputs
=
[
([],
[
'This list may not be empty.'
])
]
outputs
=
{}
field
=
serializers
.
ListField
(
child
=
serializers
.
IntegerField
(),
allow_empty
=
False
)
class
TestUnvalidatedListField
(
FieldValues
):
class
TestUnvalidatedListField
(
FieldValues
):
"""
"""
Values for `ListField` with no `child` argument.
Values for `ListField` with no `child` argument.
...
...
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