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
d934824b
Commit
d934824b
authored
Sep 05, 2014
by
Tom Christie
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Workin on
parent
c1036c17
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
159 additions
and
168 deletions
+159
-168
rest_framework/exceptions.py
+7
-2
rest_framework/fields.py
+22
-4
rest_framework/generics.py
+1
-29
rest_framework/mixins.py
+47
-36
rest_framework/serializers.py
+41
-23
tests/test_generics.py
+5
-36
tests/test_validation.py
+2
-3
tests/test_write_only_fields.py
+34
-35
No files found.
rest_framework/exceptions.py
View file @
d934824b
...
@@ -15,7 +15,7 @@ class APIException(Exception):
...
@@ -15,7 +15,7 @@ class APIException(Exception):
Subclasses should provide `.status_code` and `.default_detail` properties.
Subclasses should provide `.status_code` and `.default_detail` properties.
"""
"""
status_code
=
status
.
HTTP_500_INTERNAL_SERVER_ERROR
status_code
=
status
.
HTTP_500_INTERNAL_SERVER_ERROR
default_detail
=
''
default_detail
=
'
A server error occured
'
def
__init__
(
self
,
detail
=
None
):
def
__init__
(
self
,
detail
=
None
):
self
.
detail
=
detail
or
self
.
default_detail
self
.
detail
=
detail
or
self
.
default_detail
...
@@ -29,6 +29,11 @@ class ParseError(APIException):
...
@@ -29,6 +29,11 @@ class ParseError(APIException):
default_detail
=
'Malformed request.'
default_detail
=
'Malformed request.'
class
ValidationError
(
APIException
):
status_code
=
status
.
HTTP_400_BAD_REQUEST
default_detail
=
'Invalid data in request.'
class
AuthenticationFailed
(
APIException
):
class
AuthenticationFailed
(
APIException
):
status_code
=
status
.
HTTP_401_UNAUTHORIZED
status_code
=
status
.
HTTP_401_UNAUTHORIZED
default_detail
=
'Incorrect authentication credentials.'
default_detail
=
'Incorrect authentication credentials.'
...
@@ -54,7 +59,7 @@ class MethodNotAllowed(APIException):
...
@@ -54,7 +59,7 @@ class MethodNotAllowed(APIException):
class
NotAcceptable
(
APIException
):
class
NotAcceptable
(
APIException
):
status_code
=
status
.
HTTP_406_NOT_ACCEPTABLE
status_code
=
status
.
HTTP_406_NOT_ACCEPTABLE
default_detail
=
"Could not satisfy the request
's
Accept header"
default_detail
=
"Could not satisfy the request Accept header"
def
__init__
(
self
,
detail
=
None
,
available_renderers
=
None
):
def
__init__
(
self
,
detail
=
None
,
available_renderers
=
None
):
self
.
detail
=
detail
or
self
.
default_detail
self
.
detail
=
detail
or
self
.
default_detail
...
...
rest_framework/fields.py
View file @
d934824b
from
rest_framework.exceptions
import
ValidationError
from
rest_framework.utils
import
html
from
rest_framework.utils
import
html
import
inspect
import
inspect
...
@@ -59,10 +60,6 @@ def set_value(dictionary, keys, value):
...
@@ -59,10 +60,6 @@ def set_value(dictionary, keys, value):
dictionary
[
keys
[
-
1
]]
=
value
dictionary
[
keys
[
-
1
]]
=
value
class
ValidationError
(
Exception
):
pass
class
SkipField
(
Exception
):
class
SkipField
(
Exception
):
pass
pass
...
@@ -204,6 +201,22 @@ class Field(object):
...
@@ -204,6 +201,22 @@ class Field(object):
msg
=
self
.
_MISSING_ERROR_MESSAGE
.
format
(
class_name
=
class_name
,
key
=
key
)
msg
=
self
.
_MISSING_ERROR_MESSAGE
.
format
(
class_name
=
class_name
,
key
=
key
)
raise
AssertionError
(
msg
)
raise
AssertionError
(
msg
)
def
__new__
(
cls
,
*
args
,
**
kwargs
):
instance
=
super
(
Field
,
cls
)
.
__new__
(
cls
)
instance
.
_args
=
args
instance
.
_kwargs
=
kwargs
return
instance
def
__repr__
(
self
):
arg_string
=
', '
.
join
([
repr
(
val
)
for
val
in
self
.
_args
])
kwarg_string
=
', '
.
join
([
'
%
s=
%
s'
%
(
key
,
repr
(
val
))
for
key
,
val
in
self
.
_kwargs
.
items
()
])
if
arg_string
and
kwarg_string
:
arg_string
+=
', '
class_name
=
self
.
__class__
.
__name__
return
"
%
s(
%
s
%
s)"
%
(
class_name
,
arg_string
,
kwarg_string
)
class
BooleanField
(
Field
):
class
BooleanField
(
Field
):
MESSAGES
=
{
MESSAGES
=
{
...
@@ -308,6 +321,11 @@ class IntegerField(Field):
...
@@ -308,6 +321,11 @@ class IntegerField(Field):
'invalid_integer'
:
'A valid integer is required.'
'invalid_integer'
:
'A valid integer is required.'
}
}
def
__init__
(
self
,
**
kwargs
):
self
.
max_value
=
kwargs
.
pop
(
'max_value'
)
self
.
min_value
=
kwargs
.
pop
(
'min_value'
)
super
(
CharField
,
self
)
.
__init__
(
**
kwargs
)
def
to_native
(
self
,
data
):
def
to_native
(
self
,
data
):
try
:
try
:
data
=
int
(
str
(
data
))
data
=
int
(
str
(
data
))
...
...
rest_framework/generics.py
View file @
d934824b
...
@@ -27,7 +27,7 @@ def strict_positive_int(integer_string, cutoff=None):
...
@@ -27,7 +27,7 @@ def strict_positive_int(integer_string, cutoff=None):
def
get_object_or_404
(
queryset
,
*
filter_args
,
**
filter_kwargs
):
def
get_object_or_404
(
queryset
,
*
filter_args
,
**
filter_kwargs
):
"""
"""
Same as Django's standard shortcut, but make sure to raise 404
Same as Django's standard shortcut, but make sure to
also
raise 404
if the filter_kwargs don't match the required types.
if the filter_kwargs don't match the required types.
"""
"""
try
:
try
:
...
@@ -249,34 +249,6 @@ class GenericAPIView(views.APIView):
...
@@ -249,34 +249,6 @@ class GenericAPIView(views.APIView):
#
#
# The are not called by GenericAPIView directly,
# The are not called by GenericAPIView directly,
# but are used by the mixin methods.
# but are used by the mixin methods.
def
pre_save
(
self
,
obj
):
"""
Placeholder method for calling before saving an object.
May be used to set attributes on the object that are implicit
in either the request, or the url.
"""
pass
def
post_save
(
self
,
obj
,
created
=
False
):
"""
Placeholder method for calling after saving an object.
"""
pass
def
pre_delete
(
self
,
obj
):
"""
Placeholder method for calling before deleting an object.
"""
pass
def
post_delete
(
self
,
obj
):
"""
Placeholder method for calling after deleting an object.
"""
pass
def
metadata
(
self
,
request
):
def
metadata
(
self
,
request
):
"""
"""
Return a dictionary of metadata about the view.
Return a dictionary of metadata about the view.
...
...
rest_framework/mixins.py
View file @
d934824b
...
@@ -19,14 +19,10 @@ class CreateModelMixin(object):
...
@@ -19,14 +19,10 @@ class CreateModelMixin(object):
"""
"""
def
create
(
self
,
request
,
*
args
,
**
kwargs
):
def
create
(
self
,
request
,
*
args
,
**
kwargs
):
serializer
=
self
.
get_serializer
(
data
=
request
.
DATA
)
serializer
=
self
.
get_serializer
(
data
=
request
.
DATA
)
serializer
.
is_valid
(
raise_exception
=
True
)
if
serializer
.
is_valid
():
serializer
.
save
()
self
.
object
=
serializer
.
save
()
headers
=
self
.
get_success_headers
(
serializer
.
data
)
headers
=
self
.
get_success_headers
(
serializer
.
data
)
return
Response
(
serializer
.
data
,
status
=
status
.
HTTP_201_CREATED
,
headers
=
headers
)
return
Response
(
serializer
.
data
,
status
=
status
.
HTTP_201_CREATED
,
headers
=
headers
)
return
Response
(
serializer
.
errors
,
status
=
status
.
HTTP_400_BAD_REQUEST
)
def
get_success_headers
(
self
,
data
):
def
get_success_headers
(
self
,
data
):
try
:
try
:
...
@@ -40,15 +36,12 @@ class ListModelMixin(object):
...
@@ -40,15 +36,12 @@ class ListModelMixin(object):
List a queryset.
List a queryset.
"""
"""
def
list
(
self
,
request
,
*
args
,
**
kwargs
):
def
list
(
self
,
request
,
*
args
,
**
kwargs
):
self
.
object_list
=
self
.
filter_queryset
(
self
.
get_queryset
())
instance
=
self
.
filter_queryset
(
self
.
get_queryset
())
page
=
self
.
paginate_queryset
(
instance
)
# Switch between paginated or standard style responses
page
=
self
.
paginate_queryset
(
self
.
object_list
)
if
page
is
not
None
:
if
page
is
not
None
:
serializer
=
self
.
get_pagination_serializer
(
page
)
serializer
=
self
.
get_pagination_serializer
(
page
)
else
:
else
:
serializer
=
self
.
get_serializer
(
self
.
object_list
,
many
=
True
)
serializer
=
self
.
get_serializer
(
instance
,
many
=
True
)
return
Response
(
serializer
.
data
)
return
Response
(
serializer
.
data
)
...
@@ -57,8 +50,8 @@ class RetrieveModelMixin(object):
...
@@ -57,8 +50,8 @@ class RetrieveModelMixin(object):
Retrieve a model instance.
Retrieve a model instance.
"""
"""
def
retrieve
(
self
,
request
,
*
args
,
**
kwargs
):
def
retrieve
(
self
,
request
,
*
args
,
**
kwargs
):
self
.
object
=
self
.
get_object
()
instance
=
self
.
get_object
()
serializer
=
self
.
get_serializer
(
self
.
object
)
serializer
=
self
.
get_serializer
(
instance
)
return
Response
(
serializer
.
data
)
return
Response
(
serializer
.
data
)
...
@@ -68,22 +61,52 @@ class UpdateModelMixin(object):
...
@@ -68,22 +61,52 @@ class UpdateModelMixin(object):
"""
"""
def
update
(
self
,
request
,
*
args
,
**
kwargs
):
def
update
(
self
,
request
,
*
args
,
**
kwargs
):
partial
=
kwargs
.
pop
(
'partial'
,
False
)
partial
=
kwargs
.
pop
(
'partial'
,
False
)
self
.
object
=
self
.
get_object_or_none
()
instance
=
self
.
get_object
()
serializer
=
self
.
get_serializer
(
instance
,
data
=
request
.
DATA
,
partial
=
partial
)
serializer
.
is_valid
(
raise_exception
=
True
)
serializer
.
save
()
return
Response
(
serializer
.
data
)
def
partial_update
(
self
,
request
,
*
args
,
**
kwargs
):
kwargs
[
'partial'
]
=
True
return
self
.
update
(
request
,
*
args
,
**
kwargs
)
serializer
=
self
.
get_serializer
(
self
.
object
,
data
=
request
.
DATA
,
partial
=
partial
)
class
DestroyModelMixin
(
object
):
"""
Destroy a model instance.
"""
def
destroy
(
self
,
request
,
*
args
,
**
kwargs
):
instance
=
self
.
get_object
()
instance
.
delete
()
return
Response
(
status
=
status
.
HTTP_204_NO_CONTENT
)
if
not
serializer
.
is_valid
():
return
Response
(
serializer
.
errors
,
status
=
status
.
HTTP_400_BAD_REQUEST
)
if
self
.
object
is
None
:
# The AllowPUTAsCreateMixin was previously the default behaviour
# for PUT requests. This has now been removed and must be *explictly*
# included if it is the behavior that you want.
# For more info see: ...
class
AllowPUTAsCreateMixin
(
object
):
"""
The following mixin class may be used in order to support PUT-as-create
behavior for incoming requests.
"""
def
update
(
self
,
request
,
*
args
,
**
kwargs
):
partial
=
kwargs
.
pop
(
'partial'
,
False
)
instance
=
self
.
get_object_or_none
()
serializer
=
self
.
get_serializer
(
instance
,
data
=
request
.
DATA
,
partial
=
partial
)
serializer
.
is_valid
(
raise_exception
=
True
)
if
instance
is
None
:
lookup_url_kwarg
=
self
.
lookup_url_kwarg
or
self
.
lookup_field
lookup_url_kwarg
=
self
.
lookup_url_kwarg
or
self
.
lookup_field
lookup_value
=
self
.
kwargs
[
lookup_url_kwarg
]
lookup_value
=
self
.
kwargs
[
lookup_url_kwarg
]
extras
=
{
self
.
lookup_field
:
lookup_value
}
extras
=
{
self
.
lookup_field
:
lookup_value
}
se
lf
.
object
=
se
rializer
.
save
(
extras
=
extras
)
serializer
.
save
(
extras
=
extras
)
return
Response
(
serializer
.
data
,
status
=
status
.
HTTP_201_CREATED
)
return
Response
(
serializer
.
data
,
status
=
status
.
HTTP_201_CREATED
)
se
lf
.
object
=
se
rializer
.
save
()
serializer
.
save
()
return
Response
(
serializer
.
data
,
status
=
status
.
HTTP_200_OK
)
return
Response
(
serializer
.
data
)
def
partial_update
(
self
,
request
,
*
args
,
**
kwargs
):
def
partial_update
(
self
,
request
,
*
args
,
**
kwargs
):
kwargs
[
'partial'
]
=
True
kwargs
[
'partial'
]
=
True
...
@@ -103,15 +126,3 @@ class UpdateModelMixin(object):
...
@@ -103,15 +126,3 @@ class UpdateModelMixin(object):
# PATCH requests where the object does not exist should still
# PATCH requests where the object does not exist should still
# return a 404 response.
# return a 404 response.
raise
raise
class
DestroyModelMixin
(
object
):
"""
Destroy a model instance.
"""
def
destroy
(
self
,
request
,
*
args
,
**
kwargs
):
obj
=
self
.
get_object
()
self
.
pre_delete
(
obj
)
obj
.
delete
()
self
.
post_delete
(
obj
)
return
Response
(
status
=
status
.
HTTP_204_NO_CONTENT
)
rest_framework/serializers.py
View file @
d934824b
...
@@ -13,7 +13,8 @@ response content is handled by parsers and renderers.
...
@@ -13,7 +13,8 @@ response content is handled by parsers and renderers.
from
django.db
import
models
from
django.db
import
models
from
django.utils
import
six
from
django.utils
import
six
from
collections
import
namedtuple
,
OrderedDict
from
collections
import
namedtuple
,
OrderedDict
from
rest_framework.fields
import
empty
,
set_value
,
Field
,
SkipField
,
ValidationError
from
rest_framework.exceptions
import
ValidationError
from
rest_framework.fields
import
empty
,
set_value
,
Field
,
SkipField
from
rest_framework.settings
import
api_settings
from
rest_framework.settings
import
api_settings
from
rest_framework.utils
import
html
from
rest_framework.utils
import
html
import
copy
import
copy
...
@@ -34,43 +35,53 @@ FieldResult = namedtuple('FieldResult', ['field', 'value', 'error'])
...
@@ -34,43 +35,53 @@ FieldResult = namedtuple('FieldResult', ['field', 'value', 'error'])
class
BaseSerializer
(
Field
):
class
BaseSerializer
(
Field
):
"""
The BaseSerializer class provides a minimal class which may be used
for writing custom serializer implementations.
"""
def
__init__
(
self
,
instance
=
None
,
data
=
None
,
**
kwargs
):
def
__init__
(
self
,
instance
=
None
,
data
=
None
,
**
kwargs
):
super
(
BaseSerializer
,
self
)
.
__init__
(
**
kwargs
)
super
(
BaseSerializer
,
self
)
.
__init__
(
**
kwargs
)
self
.
instance
=
instance
self
.
instance
=
instance
self
.
_initial_data
=
data
self
.
_initial_data
=
data
def
to_native
(
self
,
data
):
def
to_native
(
self
,
data
):
raise
NotImplementedError
()
raise
NotImplementedError
(
'`to_native()` must be implemented.'
)
def
to_primative
(
self
,
instance
):
def
to_primative
(
self
,
instance
):
raise
NotImplementedError
()
raise
NotImplementedError
(
'`to_primative()` must be implemented.'
)
def
update
(
self
,
instance
):
def
update
(
self
,
instance
,
attrs
):
raise
NotImplementedError
()
raise
NotImplementedError
(
'`update()` must be implemented.'
)
def
create
(
self
):
def
create
(
self
,
attrs
):
raise
NotImplementedError
()
raise
NotImplementedError
(
'`create()` must be implemented.'
)
def
save
(
self
,
extras
=
None
):
def
save
(
self
,
extras
=
None
):
if
extras
is
not
None
:
if
extras
is
not
None
:
self
.
_
validated_data
.
update
(
extras
)
self
.
validated_data
.
update
(
extras
)
if
self
.
instance
is
not
None
:
if
self
.
instance
is
not
None
:
self
.
update
(
self
.
instance
)
self
.
update
(
self
.
instance
,
self
.
_validated_data
)
else
:
else
:
self
.
instance
=
self
.
create
()
self
.
instance
=
self
.
create
(
self
.
_validated_data
)
return
self
.
instance
return
self
.
instance
def
is_valid
(
self
):
def
is_valid
(
self
,
raise_exception
=
False
):
try
:
if
not
hasattr
(
self
,
'_validated_data'
):
self
.
_validated_data
=
self
.
to_native
(
self
.
_initial_data
)
try
:
except
ValidationError
as
exc
:
self
.
_validated_data
=
self
.
to_native
(
self
.
_initial_data
)
self
.
_validated_data
=
{}
except
ValidationError
as
exc
:
self
.
_errors
=
exc
.
args
[
0
]
self
.
_validated_data
=
{}
return
False
self
.
_errors
=
exc
.
detail
self
.
_errors
=
{}
else
:
return
True
self
.
_errors
=
{}
if
self
.
_errors
and
raise_exception
:
raise
ValidationError
(
self
.
_errors
)
return
not
bool
(
self
.
_errors
)
@property
@property
def
data
(
self
):
def
data
(
self
):
...
@@ -184,14 +195,20 @@ class Serializer(BaseSerializer):
...
@@ -184,14 +195,20 @@ class Serializer(BaseSerializer):
"""
"""
Dict of native values <- Dict of primitive datatypes.
Dict of native values <- Dict of primitive datatypes.
"""
"""
if
not
isinstance
(
data
,
dict
):
raise
ValidationError
({
'non_field_errors'
:
[
'Invalid data'
]})
ret
=
{}
ret
=
{}
errors
=
{}
errors
=
{}
fields
=
[
field
for
field
in
self
.
fields
.
values
()
if
not
field
.
read_only
]
fields
=
[
field
for
field
in
self
.
fields
.
values
()
if
not
field
.
read_only
]
for
field
in
fields
:
for
field
in
fields
:
validate_method
=
getattr
(
self
,
'validate_'
+
field
.
field_name
,
None
)
primitive_value
=
field
.
get_value
(
data
)
primitive_value
=
field
.
get_value
(
data
)
try
:
try
:
validated_value
=
field
.
validate
(
primitive_value
)
validated_value
=
field
.
validate
(
primitive_value
)
if
validate_method
is
not
None
:
validated_value
=
validate_method
(
validated_value
)
except
ValidationError
as
exc
:
except
ValidationError
as
exc
:
errors
[
field
.
field_name
]
=
str
(
exc
)
errors
[
field
.
field_name
]
=
str
(
exc
)
except
SkipField
:
except
SkipField
:
...
@@ -202,6 +219,7 @@ class Serializer(BaseSerializer):
...
@@ -202,6 +219,7 @@ class Serializer(BaseSerializer):
if
errors
:
if
errors
:
raise
ValidationError
(
errors
)
raise
ValidationError
(
errors
)
# TODO: 'Non field errors'
return
self
.
validate
(
ret
)
return
self
.
validate
(
ret
)
def
to_primative
(
self
,
instance
):
def
to_primative
(
self
,
instance
):
...
@@ -340,12 +358,12 @@ class ModelSerializer(Serializer):
...
@@ -340,12 +358,12 @@ class ModelSerializer(Serializer):
self
.
opts
=
self
.
_options_class
(
self
.
Meta
)
self
.
opts
=
self
.
_options_class
(
self
.
Meta
)
super
(
ModelSerializer
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
super
(
ModelSerializer
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
def
create
(
self
):
def
create
(
self
,
attrs
):
ModelClass
=
self
.
opts
.
model
ModelClass
=
self
.
opts
.
model
return
ModelClass
.
objects
.
create
(
**
self
.
validated_data
)
return
ModelClass
.
objects
.
create
(
**
attrs
)
def
update
(
self
,
obj
):
def
update
(
self
,
obj
,
attrs
):
for
attr
,
value
in
self
.
validated_data
.
items
():
for
attr
,
value
in
attrs
.
items
():
setattr
(
obj
,
attr
,
value
)
setattr
(
obj
,
attr
,
value
)
obj
.
save
()
obj
.
save
()
...
...
tests/test_generics.py
View file @
d934824b
...
@@ -360,18 +360,15 @@ class TestInstanceView(TestCase):
...
@@ -360,18 +360,15 @@ class TestInstanceView(TestCase):
def
test_put_to_deleted_instance
(
self
):
def
test_put_to_deleted_instance
(
self
):
"""
"""
PUT requests to RetrieveUpdateDestroyAPIView should
create an object
PUT requests to RetrieveUpdateDestroyAPIView should
return 404 if
if i
t does not currently exist.
an objec
t does not currently exist.
"""
"""
self
.
objects
.
get
(
id
=
1
)
.
delete
()
self
.
objects
.
get
(
id
=
1
)
.
delete
()
data
=
{
'text'
:
'foobar'
}
data
=
{
'text'
:
'foobar'
}
request
=
factory
.
put
(
'/1'
,
data
,
format
=
'json'
)
request
=
factory
.
put
(
'/1'
,
data
,
format
=
'json'
)
with
self
.
assertNumQueries
(
2
):
with
self
.
assertNumQueries
(
1
):
response
=
self
.
view
(
request
,
pk
=
1
)
.
render
()
response
=
self
.
view
(
request
,
pk
=
1
)
.
render
()
self
.
assertEqual
(
response
.
status_code
,
status
.
HTTP_201_CREATED
)
self
.
assertEqual
(
response
.
status_code
,
status
.
HTTP_404_NOT_FOUND
)
self
.
assertEqual
(
response
.
data
,
{
'id'
:
1
,
'text'
:
'foobar'
})
updated
=
self
.
objects
.
get
(
id
=
1
)
self
.
assertEqual
(
updated
.
text
,
'foobar'
)
def
test_put_to_filtered_out_instance
(
self
):
def
test_put_to_filtered_out_instance
(
self
):
"""
"""
...
@@ -382,35 +379,7 @@ class TestInstanceView(TestCase):
...
@@ -382,35 +379,7 @@ class TestInstanceView(TestCase):
filtered_out_pk
=
BasicModel
.
objects
.
filter
(
text
=
'filtered out'
)[
0
]
.
pk
filtered_out_pk
=
BasicModel
.
objects
.
filter
(
text
=
'filtered out'
)[
0
]
.
pk
request
=
factory
.
put
(
'/{0}'
.
format
(
filtered_out_pk
),
data
,
format
=
'json'
)
request
=
factory
.
put
(
'/{0}'
.
format
(
filtered_out_pk
),
data
,
format
=
'json'
)
response
=
self
.
view
(
request
,
pk
=
filtered_out_pk
)
.
render
()
response
=
self
.
view
(
request
,
pk
=
filtered_out_pk
)
.
render
()
self
.
assertEqual
(
response
.
status_code
,
status
.
HTTP_400_BAD_REQUEST
)
self
.
assertEqual
(
response
.
status_code
,
status
.
HTTP_404_NOT_FOUND
)
def
test_put_as_create_on_id_based_url
(
self
):
"""
PUT requests to RetrieveUpdateDestroyAPIView should create an object
at the requested url if it doesn't exist.
"""
data
=
{
'text'
:
'foobar'
}
# pk fields can not be created on demand, only the database can set the pk for a new object
request
=
factory
.
put
(
'/5'
,
data
,
format
=
'json'
)
with
self
.
assertNumQueries
(
2
):
response
=
self
.
view
(
request
,
pk
=
5
)
.
render
()
self
.
assertEqual
(
response
.
status_code
,
status
.
HTTP_201_CREATED
)
new_obj
=
self
.
objects
.
get
(
pk
=
5
)
self
.
assertEqual
(
new_obj
.
text
,
'foobar'
)
def
test_put_as_create_on_slug_based_url
(
self
):
"""
PUT requests to RetrieveUpdateDestroyAPIView should create an object
at the requested url if possible, else return HTTP_403_FORBIDDEN error-response.
"""
data
=
{
'text'
:
'foobar'
}
request
=
factory
.
put
(
'/test_slug'
,
data
,
format
=
'json'
)
with
self
.
assertNumQueries
(
2
):
response
=
self
.
slug_based_view
(
request
,
slug
=
'test_slug'
)
.
render
()
self
.
assertEqual
(
response
.
status_code
,
status
.
HTTP_201_CREATED
)
self
.
assertEqual
(
response
.
data
,
{
'slug'
:
'test_slug'
,
'text'
:
'foobar'
})
new_obj
=
SlugBasedModel
.
objects
.
get
(
slug
=
'test_slug'
)
self
.
assertEqual
(
new_obj
.
text
,
'foobar'
)
def
test_patch_cannot_create_an_object
(
self
):
def
test_patch_cannot_create_an_object
(
self
):
"""
"""
...
...
tests/test_validation.py
View file @
d934824b
...
@@ -48,11 +48,10 @@ class ShouldValidateModel(models.Model):
...
@@ -48,11 +48,10 @@ class ShouldValidateModel(models.Model):
class
ShouldValidateModelSerializer
(
serializers
.
ModelSerializer
):
class
ShouldValidateModelSerializer
(
serializers
.
ModelSerializer
):
renamed
=
serializers
.
CharField
(
source
=
'should_validate_field'
,
required
=
False
)
renamed
=
serializers
.
CharField
(
source
=
'should_validate_field'
,
required
=
False
)
def
validate_renamed
(
self
,
attrs
,
source
):
def
validate_renamed
(
self
,
value
):
value
=
attrs
[
source
]
if
len
(
value
)
<
3
:
if
len
(
value
)
<
3
:
raise
serializers
.
ValidationError
(
'Minimum 3 characters.'
)
raise
serializers
.
ValidationError
(
'Minimum 3 characters.'
)
return
attrs
return
value
class
Meta
:
class
Meta
:
model
=
ShouldValidateModel
model
=
ShouldValidateModel
...
...
tests/test_write_only_fields.py
View file @
d934824b
from
django.db
import
models
#
from django.db import models
from
django.test
import
TestCase
#
from django.test import TestCase
from
rest_framework
import
serializers
#
from rest_framework import serializers
class
ExampleModel
(
models
.
Model
):
#
class ExampleModel(models.Model):
email
=
models
.
EmailField
(
max_length
=
100
)
#
email = models.EmailField(max_length=100)
password
=
models
.
CharField
(
max_length
=
100
)
#
password = models.CharField(max_length=100)
class
WriteOnlyFieldTests
(
TestCase
):
#
class WriteOnlyFieldTests(TestCase):
def
test_write_only_fields
(
self
):
#
def test_write_only_fields(self):
class
ExampleSerializer
(
serializers
.
Serializer
):
#
class ExampleSerializer(serializers.Serializer):
email
=
serializers
.
EmailField
()
#
email = serializers.EmailField()
password
=
serializers
.
CharField
(
write_only
=
True
)
#
password = serializers.CharField(write_only=True)
data
=
{
#
data = {
'email'
:
'foo@example.com'
,
#
'email': 'foo@example.com',
'password'
:
'123'
#
'password': '123'
}
#
}
serializer
=
ExampleSerializer
(
data
=
data
)
#
serializer = ExampleSerializer(data=data)
self
.
assertTrue
(
serializer
.
is_valid
())
#
self.assertTrue(serializer.is_valid())
self
.
assertEquals
(
serializer
.
object
,
data
)
# self.assertEquals(serializer.validated_data
, data)
self
.
assertEquals
(
serializer
.
data
,
{
'email'
:
'foo@example.com'
})
#
self.assertEquals(serializer.data, {'email': 'foo@example.com'})
def
test_write_only_fields_meta
(
self
):
#
def test_write_only_fields_meta(self):
class
ExampleSerializer
(
serializers
.
ModelSerializer
):
#
class ExampleSerializer(serializers.ModelSerializer):
class
Meta
:
#
class Meta:
model
=
ExampleModel
#
model = ExampleModel
fields
=
(
'email'
,
'password'
)
#
fields = ('email', 'password')
write_only_fields
=
(
'password'
,)
#
write_only_fields = ('password',)
data
=
{
# data = {
'email'
:
'foo@example.com'
,
# 'email': 'foo@example.com',
'password'
:
'123'
# 'password': '123'
}
# }
serializer
=
ExampleSerializer
(
data
=
data
)
# serializer = ExampleSerializer(data=data)
self
.
assertTrue
(
serializer
.
is_valid
())
# self.assertTrue(serializer.is_valid())
self
.
assertTrue
(
isinstance
(
serializer
.
object
,
ExampleModel
))
# self.assertTrue(isinstance(serializer.object, ExampleModel))
self
.
assertEquals
(
serializer
.
object
.
email
,
data
[
'email'
])
# self.assertEquals(serializer.validated_data, data)
self
.
assertEquals
(
serializer
.
object
.
password
,
data
[
'password'
])
# self.assertEquals(serializer.data, {'email': 'foo@example.com'})
self
.
assertEquals
(
serializer
.
data
,
{
'email'
:
'foo@example.com'
})
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