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
eee02a47
Commit
eee02a47
authored
Dec 08, 2014
by
Tom Christie
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added ListSerializer.validate(). Closes #2168.
parent
ef89c156
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
108 additions
and
54 deletions
+108
-54
rest_framework/fields.py
+27
-11
rest_framework/serializers.py
+65
-43
tests/test_serializer_lists.py
+16
-0
No files found.
rest_framework/fields.py
View file @
eee02a47
...
...
@@ -294,31 +294,47 @@ class Field(object):
return
self
.
default
()
return
self
.
default
def
run_validation
(
self
,
data
=
empty
):
def
validate_empty_values
(
self
,
data
):
"""
Validate a simple representation and return the internal value.
The provided data may be `empty` if no representation was included
in the input.
May raise `SkipField` if the field should not be included in the
validated data.
Validate empty values, and either:
* Raise `ValidationError`, indicating invalid data.
* Raise `SkipField`, indicating that the field should be ignored.
* Return (True, data), indicating an empty value that should be
returned without any furhter validation being applied.
* Return (False, data), indicating a non-empty value, that should
have validation applied as normal.
"""
if
self
.
read_only
:
return
self
.
get_default
(
)
return
(
True
,
self
.
get_default
()
)
if
data
is
empty
:
if
getattr
(
self
.
root
,
'partial'
,
False
):
raise
SkipField
()
if
self
.
required
:
self
.
fail
(
'required'
)
return
self
.
get_default
(
)
return
(
True
,
self
.
get_default
()
)
if
data
is
None
:
if
not
self
.
allow_null
:
self
.
fail
(
'null'
)
return
None
return
(
True
,
None
)
return
(
False
,
data
)
def
run_validation
(
self
,
data
=
empty
):
"""
Validate a simple representation and return the internal value.
The provided data may be `empty` if no representation was included
in the input.
May raise `SkipField` if the field should not be included in the
validated data.
"""
(
is_empty_value
,
data
)
=
self
.
validate_empty_values
(
data
)
if
is_empty_value
:
return
data
value
=
self
.
to_internal_value
(
data
)
self
.
run_validators
(
value
)
return
value
...
...
rest_framework/serializers.py
View file @
eee02a47
...
...
@@ -229,6 +229,35 @@ class SerializerMetaclass(type):
return
super
(
SerializerMetaclass
,
cls
)
.
__new__
(
cls
,
name
,
bases
,
attrs
)
def
get_validation_error_detail
(
exc
):
assert
isinstance
(
exc
,
(
ValidationError
,
DjangoValidationError
))
if
isinstance
(
exc
,
DjangoValidationError
):
# Normally you should raise `serializers.ValidationError`
# inside your codebase, but we handle Django's validation
# exception class as well for simpler compat.
# Eg. Calling Model.clean() explicitly inside Serializer.validate()
return
{
api_settings
.
NON_FIELD_ERRORS_KEY
:
list
(
exc
.
messages
)
}
elif
isinstance
(
exc
.
detail
,
dict
):
# If errors may be a dict we use the standard {key: list of values}.
# Here we ensure that all the values are *lists* of errors.
return
dict
([
(
key
,
value
if
isinstance
(
value
,
list
)
else
[
value
])
for
key
,
value
in
exc
.
detail
.
items
()
])
elif
isinstance
(
exc
.
detail
,
list
):
# Errors raised as a list are non-field errors.
return
{
api_settings
.
NON_FIELD_ERRORS_KEY
:
exc
.
detail
}
# Errors raised as a string are non-field errors.
return
{
api_settings
.
NON_FIELD_ERRORS_KEY
:
[
exc
.
detail
]
}
@six.add_metaclass
(
SerializerMetaclass
)
class
Serializer
(
BaseSerializer
):
default_error_messages
=
{
...
...
@@ -293,55 +322,17 @@ class Serializer(BaseSerializer):
performed by validators and the `.validate()` method should
be coerced into an error dictionary with a 'non_fields_error' key.
"""
if
data
is
empty
:
if
getattr
(
self
.
root
,
'partial'
,
False
):
raise
SkipField
()
if
self
.
required
:
self
.
fail
(
'required'
)
return
self
.
get_default
()
if
data
is
None
:
if
not
self
.
allow_null
:
self
.
fail
(
'null'
)
return
None
if
not
isinstance
(
data
,
dict
):
message
=
self
.
error_messages
[
'invalid'
]
.
format
(
datatype
=
type
(
data
)
.
__name__
)
raise
ValidationError
({
api_settings
.
NON_FIELD_ERRORS_KEY
:
[
message
]
})
(
is_empty_value
,
data
)
=
self
.
validate_empty_values
(
data
)
if
is_empty_value
:
return
data
value
=
self
.
to_internal_value
(
data
)
try
:
self
.
run_validators
(
value
)
value
=
self
.
validate
(
value
)
assert
value
is
not
None
,
'.validate() should return the validated data'
except
ValidationError
as
exc
:
if
isinstance
(
exc
.
detail
,
dict
):
# .validate() errors may be a dict, in which case, use
# standard {key: list of values} style.
raise
ValidationError
(
dict
([
(
key
,
value
if
isinstance
(
value
,
list
)
else
[
value
])
for
key
,
value
in
exc
.
detail
.
items
()
]))
elif
isinstance
(
exc
.
detail
,
list
):
raise
ValidationError
({
api_settings
.
NON_FIELD_ERRORS_KEY
:
exc
.
detail
})
else
:
raise
ValidationError
({
api_settings
.
NON_FIELD_ERRORS_KEY
:
[
exc
.
detail
]
})
except
DjangoValidationError
as
exc
:
# Normally you should raise `serializers.ValidationError`
# inside your codebase, but we handle Django's validation
# exception class as well for simpler compat.
# Eg. Calling Model.clean() explicitly inside Serializer.validate()
raise
ValidationError
({
api_settings
.
NON_FIELD_ERRORS_KEY
:
list
(
exc
.
messages
)
})
except
(
ValidationError
,
DjangoValidationError
)
as
exc
:
raise
ValidationError
(
detail
=
get_validation_error_detail
(
exc
))
return
value
...
...
@@ -349,6 +340,14 @@ class Serializer(BaseSerializer):
"""
Dict of native values <- Dict of primitive datatypes.
"""
if
not
isinstance
(
data
,
dict
):
message
=
self
.
error_messages
[
'invalid'
]
.
format
(
datatype
=
type
(
data
)
.
__name__
)
raise
ValidationError
({
api_settings
.
NON_FIELD_ERRORS_KEY
:
[
message
]
})
ret
=
OrderedDict
()
errors
=
OrderedDict
()
fields
=
[
...
...
@@ -462,6 +461,26 @@ class ListSerializer(BaseSerializer):
return
html
.
parse_html_list
(
dictionary
,
prefix
=
self
.
field_name
)
return
dictionary
.
get
(
self
.
field_name
,
empty
)
def
run_validation
(
self
,
data
=
empty
):
"""
We override the default `run_validation`, because the validation
performed by validators and the `.validate()` method should
be coerced into an error dictionary with a 'non_fields_error' key.
"""
(
is_empty_value
,
data
)
=
self
.
validate_empty_values
(
data
)
if
is_empty_value
:
return
data
value
=
self
.
to_internal_value
(
data
)
try
:
self
.
run_validators
(
value
)
value
=
self
.
validate
(
value
)
assert
value
is
not
None
,
'.validate() should return the validated data'
except
(
ValidationError
,
DjangoValidationError
)
as
exc
:
raise
ValidationError
(
detail
=
get_validation_error_detail
(
exc
))
return
value
def
to_internal_value
(
self
,
data
):
"""
List of dicts of native values <- List of dicts of primitive datatypes.
...
...
@@ -503,6 +522,9 @@ class ListSerializer(BaseSerializer):
self
.
child
.
to_representation
(
item
)
for
item
in
iterable
]
def
validate
(
self
,
attrs
):
return
attrs
def
update
(
self
,
instance
,
validated_data
):
raise
NotImplementedError
(
"Serializers with many=True do not support multiple update by "
...
...
tests/test_serializer_lists.py
View file @
eee02a47
...
...
@@ -272,3 +272,19 @@ class TestNestedListOfListsSerializer:
serializer
=
self
.
Serializer
(
data
=
input_data
)
assert
serializer
.
is_valid
()
assert
serializer
.
validated_data
==
expected_output
class
TestListSerializerClass
:
"""Tests for a custom list_serializer_class."""
def
test_list_serializer_class_validate
(
self
):
class
CustomListSerializer
(
serializers
.
ListSerializer
):
def
validate
(
self
,
attrs
):
raise
serializers
.
ValidationError
(
'Non field error'
)
class
TestSerializer
(
serializers
.
Serializer
):
class
Meta
:
list_serializer_class
=
CustomListSerializer
serializer
=
TestSerializer
(
data
=
[],
many
=
True
)
assert
not
serializer
.
is_valid
()
assert
serializer
.
errors
==
{
'non_field_errors'
:
[
'Non field error'
]}
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