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
f2852811
Commit
f2852811
authored
Sep 02, 2014
by
Tom Christie
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Getting tests passing
parent
ec096a1c
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
3737 additions
and
3725 deletions
+3737
-3725
rest_framework/authtoken/serializers.py
+3
-2
rest_framework/authtoken/views.py
+2
-1
rest_framework/fields.py
+49
-1
rest_framework/mixins.py
+4
-37
rest_framework/pagination.py
+12
-24
rest_framework/relations.py
+1
-1
rest_framework/serializers.py
+32
-21
tests/test_fields.py
+960
-960
tests/test_files.py
+92
-92
tests/test_genericrelations.py
+151
-151
tests/test_generics.py
+177
-181
tests/test_hyperlinkedserializers.py
+362
-362
tests/test_nullable_fields.py
+27
-27
tests/test_pagination.py
+4
-4
tests/test_permissions.py
+53
-53
tests/test_relations.py
+149
-149
tests/test_relations_hyperlink.py
+525
-525
tests/test_relations_nested.py
+326
-326
tests/test_relations_pk.py
+551
-551
tests/test_relations_slug.py
+257
-257
No files found.
rest_framework/authtoken/serializers.py
View file @
f2852811
...
...
@@ -19,11 +19,12 @@ class AuthTokenSerializer(serializers.Serializer):
if
not
user
.
is_active
:
msg
=
_
(
'User account is disabled.'
)
raise
serializers
.
ValidationError
(
msg
)
attrs
[
'user'
]
=
user
return
attrs
else
:
msg
=
_
(
'Unable to login with provided credentials.'
)
raise
serializers
.
ValidationError
(
msg
)
else
:
msg
=
_
(
'Must include "username" and "password"'
)
raise
serializers
.
ValidationError
(
msg
)
attrs
[
'user'
]
=
user
return
attrs
rest_framework/authtoken/views.py
View file @
f2852811
...
...
@@ -18,7 +18,8 @@ class ObtainAuthToken(APIView):
def
post
(
self
,
request
):
serializer
=
self
.
serializer_class
(
data
=
request
.
DATA
)
if
serializer
.
is_valid
():
token
,
created
=
Token
.
objects
.
get_or_create
(
user
=
serializer
.
object
[
'user'
])
user
=
serializer
.
validated_data
[
'user'
]
token
,
created
=
Token
.
objects
.
get_or_create
(
user
=
user
)
return
Response
({
'token'
:
token
.
key
})
return
Response
(
serializer
.
errors
,
status
=
status
.
HTTP_400_BAD_REQUEST
)
...
...
rest_framework/fields.py
View file @
f2852811
from
rest_framework.utils
import
html
import
inspect
class
empty
:
...
...
@@ -11,6 +12,22 @@ class empty:
pass
def
is_simple_callable
(
obj
):
"""
True if the object is a callable that takes no arguments.
"""
function
=
inspect
.
isfunction
(
obj
)
method
=
inspect
.
ismethod
(
obj
)
if
not
(
function
or
method
):
return
False
args
,
_
,
_
,
defaults
=
inspect
.
getargspec
(
obj
)
len_args
=
len
(
args
)
if
function
else
len
(
args
)
-
1
len_defaults
=
len
(
defaults
)
if
defaults
else
0
return
len_args
<=
len_defaults
def
get_attribute
(
instance
,
attrs
):
"""
Similar to Python's built in `getattr(instance, attr)`,
...
...
@@ -98,6 +115,7 @@ class Field(object):
self
.
field_name
=
field_name
self
.
parent
=
parent
self
.
root
=
root
self
.
context
=
parent
.
context
# `self.label` should deafult to being based on the field name.
if
self
.
label
is
None
:
...
...
@@ -297,25 +315,55 @@ class IntegerField(Field):
self
.
fail
(
'invalid_integer'
)
return
data
def
to_primative
(
self
,
value
):
if
value
is
None
:
return
None
return
int
(
value
)
class
EmailField
(
CharField
):
pass
# TODO
class
URLField
(
CharField
):
pass
# TODO
class
RegexField
(
CharField
):
def
__init__
(
self
,
**
kwargs
):
self
.
regex
=
kwargs
.
pop
(
'regex'
)
super
(
CharField
,
self
)
.
__init__
(
**
kwargs
)
class
DateField
(
CharField
):
def
__init__
(
self
,
**
kwargs
):
self
.
input_formats
=
kwargs
.
pop
(
'input_formats'
,
None
)
super
(
DateField
,
self
)
.
__init__
(
**
kwargs
)
class
TimeField
(
CharField
):
def
__init__
(
self
,
**
kwargs
):
self
.
input_formats
=
kwargs
.
pop
(
'input_formats'
,
None
)
super
(
TimeField
,
self
)
.
__init__
(
**
kwargs
)
class
DateTimeField
(
CharField
):
pass
# TODO
def
__init__
(
self
,
**
kwargs
):
self
.
input_formats
=
kwargs
.
pop
(
'input_formats'
,
None
)
super
(
DateTimeField
,
self
)
.
__init__
(
**
kwargs
)
class
FileField
(
Field
):
pass
# TODO
class
ReadOnlyField
(
Field
):
def
to_primative
(
self
,
value
):
if
is_simple_callable
(
value
):
return
value
()
return
value
class
MethodField
(
Field
):
def
__init__
(
self
,
**
kwargs
):
kwargs
[
'source'
]
=
'*'
...
...
rest_framework/mixins.py
View file @
f2852811
...
...
@@ -13,23 +13,6 @@ from rest_framework.request import clone_request
from
rest_framework.settings
import
api_settings
def
_get_validation_exclusions
(
obj
,
lookup_field
=
None
):
"""
Given a model instance, and an optional pk and slug field,
return the full list of all other field names on that model.
For use when performing full_clean on a model instance,
so we only clean the required fields.
"""
if
lookup_field
==
'pk'
:
pk_field
=
obj
.
_meta
.
pk
while
pk_field
.
rel
:
pk_field
=
pk_field
.
rel
.
to
.
_meta
.
pk
lookup_field
=
pk_field
.
name
return
[
field
.
name
for
field
in
obj
.
_meta
.
fields
if
field
.
name
!=
lookup_field
]
class
CreateModelMixin
(
object
):
"""
Create a model instance.
...
...
@@ -92,15 +75,14 @@ class UpdateModelMixin(object):
if
not
serializer
.
is_valid
():
return
Response
(
serializer
.
errors
,
status
=
status
.
HTTP_400_BAD_REQUEST
)
lookup_url_kwarg
=
self
.
lookup_url_kwarg
or
self
.
lookup_field
lookup_value
=
self
.
kwargs
[
lookup_url_kwarg
]
extras
=
{
self
.
lookup_field
:
lookup_value
}
if
self
.
object
is
None
:
lookup_url_kwarg
=
self
.
lookup_url_kwarg
or
self
.
lookup_field
lookup_value
=
self
.
kwargs
[
lookup_url_kwarg
]
extras
=
{
self
.
lookup_field
:
lookup_value
}
self
.
object
=
serializer
.
save
(
extras
=
extras
)
return
Response
(
serializer
.
data
,
status
=
status
.
HTTP_201_CREATED
)
self
.
object
=
serializer
.
save
(
extras
=
extras
)
self
.
object
=
serializer
.
save
()
return
Response
(
serializer
.
data
,
status
=
status
.
HTTP_200_OK
)
def
partial_update
(
self
,
request
,
*
args
,
**
kwargs
):
...
...
@@ -122,21 +104,6 @@ class UpdateModelMixin(object):
# return a 404 response.
raise
def
pre_save
(
self
,
obj
):
"""
Set any attributes on the object that are implicit in the request.
"""
lookup_url_kwarg
=
self
.
lookup_url_kwarg
or
self
.
lookup_field
lookup_value
=
self
.
kwargs
[
lookup_url_kwarg
]
setattr
(
obj
,
self
.
lookup_field
,
lookup_value
)
# Ensure we clean the attributes so that we don't eg return integer
# pk using a string representation, as provided by the url conf kwarg.
if
hasattr
(
obj
,
'full_clean'
):
exclude
=
_get_validation_exclusions
(
obj
,
self
.
lookup_field
)
obj
.
full_clean
(
exclude
)
class
DestroyModelMixin
(
object
):
"""
...
...
rest_framework/pagination.py
View file @
f2852811
...
...
@@ -13,7 +13,7 @@ class NextPageField(serializers.Field):
"""
page_field
=
'page'
def
to_
n
ative
(
self
,
value
):
def
to_
prim
ative
(
self
,
value
):
if
not
value
.
has_next
():
return
None
page
=
value
.
next_page_number
()
...
...
@@ -28,7 +28,7 @@ class PreviousPageField(serializers.Field):
"""
page_field
=
'page'
def
to_
n
ative
(
self
,
value
):
def
to_
prim
ative
(
self
,
value
):
if
not
value
.
has_previous
():
return
None
page
=
value
.
previous_page_number
()
...
...
@@ -48,25 +48,11 @@ class DefaultObjectSerializer(serializers.Field):
super
(
DefaultObjectSerializer
,
self
)
.
__init__
(
source
=
source
)
# class PaginationSerializerOptions(serializers.SerializerOptions):
# """
# An object that stores the options that may be provided to a
# pagination serializer by using the inner `Meta` class.
# Accessible on the instance as `serializer.opts`.
# """
# def __init__(self, meta):
# super(PaginationSerializerOptions, self).__init__(meta)
# self.object_serializer_class = getattr(meta, 'object_serializer_class',
# DefaultObjectSerializer)
class
BasePaginationSerializer
(
serializers
.
Serializer
):
"""
A base class for pagination serializers to inherit from,
to make implementing custom serializers more easy.
"""
# _options_class = PaginationSerializerOptions
results_field
=
'results'
def
__init__
(
self
,
*
args
,
**
kwargs
):
...
...
@@ -75,14 +61,16 @@ class BasePaginationSerializer(serializers.Serializer):
"""
super
(
BasePaginationSerializer
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
results_field
=
self
.
results_field
object_serializer
=
self
.
opts
.
object_serializer_class
if
'context'
in
kwargs
:
context_kwarg
=
{
'context'
:
kwargs
[
'context'
]}
else
:
context_kwarg
=
{}
self
.
fields
[
results_field
]
=
object_serializer
(
source
=
'object_list'
,
**
context_kwarg
)
try
:
object_serializer
=
self
.
Meta
.
object_serializer_class
except
AttributeError
:
object_serializer
=
DefaultObjectSerializer
self
.
fields
[
results_field
]
=
serializers
.
ListSerializer
(
child
=
object_serializer
(),
source
=
'object_list'
)
self
.
fields
[
results_field
]
.
bind
(
results_field
,
self
,
self
)
# TODO: Support automatic binding
class
PaginationSerializer
(
BasePaginationSerializer
):
...
...
rest_framework/relations.py
View file @
f2852811
...
...
@@ -73,7 +73,7 @@ class HyperlinkedRelatedField(RelatedField):
try
:
http_prefix
=
value
.
startswith
((
'http:'
,
'https:'
))
except
AttributeError
:
self
.
fail
(
'incorrect_type'
,
type
(
value
)
.
__name__
)
self
.
fail
(
'incorrect_type'
,
data_type
=
type
(
value
)
.
__name__
)
if
http_prefix
:
# If needed convert absolute URLs to relative path
...
...
rest_framework/serializers.py
View file @
f2852811
...
...
@@ -142,7 +142,7 @@ class Serializer(BaseSerializer):
return
super
(
Serializer
,
cls
)
.
__new__
(
cls
)
def
__init__
(
self
,
*
args
,
**
kwargs
):
kwargs
.
pop
(
'context'
,
None
)
self
.
context
=
kwargs
.
pop
(
'context'
,
{}
)
kwargs
.
pop
(
'partial'
,
None
)
kwargs
.
pop
(
'many'
,
False
)
...
...
@@ -202,7 +202,7 @@ class Serializer(BaseSerializer):
if
errors
:
raise
ValidationError
(
errors
)
return
ret
return
self
.
validate
(
ret
)
def
to_primative
(
self
,
instance
):
"""
...
...
@@ -217,6 +217,9 @@ class Serializer(BaseSerializer):
return
ret
def
validate
(
self
,
attrs
):
return
attrs
def
__iter__
(
self
):
errors
=
self
.
errors
if
hasattr
(
self
,
'_errors'
)
else
{}
for
field
in
self
.
fields
.
values
():
...
...
@@ -232,8 +235,7 @@ class ListSerializer(BaseSerializer):
def
__init__
(
self
,
*
args
,
**
kwargs
):
self
.
child
=
kwargs
.
pop
(
'child'
,
copy
.
deepcopy
(
self
.
child
))
assert
self
.
child
is
not
None
,
'`child` is a required argument.'
kwargs
.
pop
(
'context'
,
None
)
self
.
context
=
kwargs
.
pop
(
'context'
,
{})
kwargs
.
pop
(
'partial'
,
None
)
super
(
ListSerializer
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
...
...
@@ -316,19 +318,19 @@ class ModelSerializer(Serializer):
models
.
PositiveIntegerField
:
IntegerField
,
models
.
SmallIntegerField
:
IntegerField
,
models
.
PositiveSmallIntegerField
:
IntegerField
,
#
models.DateTimeField: DateTimeField,
#
models.DateField: DateField,
#
models.TimeField: TimeField,
models
.
DateTimeField
:
DateTimeField
,
models
.
DateField
:
DateField
,
models
.
TimeField
:
TimeField
,
# models.DecimalField: DecimalField,
#
models.EmailField: EmailField,
models
.
EmailField
:
EmailField
,
models
.
CharField
:
CharField
,
#
models.URLField: URLField,
models
.
URLField
:
URLField
,
# models.SlugField: SlugField,
models
.
TextField
:
CharField
,
models
.
CommaSeparatedIntegerField
:
CharField
,
models
.
BooleanField
:
BooleanField
,
models
.
NullBooleanField
:
BooleanField
,
#
models.FileField: FileField,
models
.
FileField
:
FileField
,
# models.ImageField: ImageField,
}
...
...
@@ -338,6 +340,15 @@ class ModelSerializer(Serializer):
self
.
opts
=
self
.
_options_class
(
self
.
Meta
)
super
(
ModelSerializer
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
def
create
(
self
):
ModelClass
=
self
.
opts
.
model
return
ModelClass
.
objects
.
create
(
**
self
.
validated_data
)
def
update
(
self
,
obj
):
for
attr
,
value
in
self
.
validated_data
.
items
():
setattr
(
obj
,
attr
,
value
)
obj
.
save
()
def
get_fields
(
self
):
# Get the explicitly declared fields.
fields
=
copy
.
deepcopy
(
self
.
base_fields
)
...
...
@@ -566,8 +577,8 @@ class HyperlinkedModelSerializerOptions(ModelSerializerOptions):
class
HyperlinkedModelSerializer
(
ModelSerializer
):
_options_class
=
HyperlinkedModelSerializerOptions
_default_view_name
=
'
%(model_name)
s-detail'
#
_hyperlink_field_class = HyperlinkedRelatedField
#
_hyperlink_identify_field_class = HyperlinkedIdentityField
_hyperlink_field_class
=
HyperlinkedRelatedField
_hyperlink_identify_field_class
=
HyperlinkedIdentityField
def
get_default_fields
(
self
):
fields
=
super
(
HyperlinkedModelSerializer
,
self
)
.
get_default_fields
()
...
...
@@ -575,15 +586,15 @@ class HyperlinkedModelSerializer(ModelSerializer):
if
self
.
opts
.
view_name
is
None
:
self
.
opts
.
view_name
=
self
.
_get_default_view_name
(
self
.
opts
.
model
)
#
if self.opts.url_field_name not in fields:
#
url_field = self._hyperlink_identify_field_class(
#
view_name=self.opts.view_name,
#
lookup_field=self.opts.lookup_field
#
)
# ret = self._dict_class
()
#
ret[self.opts.url_field_name] = url_field
#
ret.update(fields)
#
fields = ret
if
self
.
opts
.
url_field_name
not
in
fields
:
url_field
=
self
.
_hyperlink_identify_field_class
(
view_name
=
self
.
opts
.
view_name
,
lookup_field
=
self
.
opts
.
lookup_field
)
ret
=
fields
.
__class__
()
ret
[
self
.
opts
.
url_field_name
]
=
url_field
ret
.
update
(
fields
)
fields
=
ret
return
fields
...
...
tests/test_fields.py
View file @
f2852811
"""
General serializer field tests.
"""
from
__future__
import
unicode_literals
#
"""
#
General serializer field tests.
#
"""
#
from __future__ import unicode_literals
import
datetime
import
re
from
decimal
import
Decimal
from
uuid
import
uuid4
from
django.core
import
validators
from
django.db
import
models
from
django.test
import
TestCase
from
django.utils.datastructures
import
SortedDict
from
rest_framework
import
serializers
from
tests.models
import
RESTFrameworkModel
#
import datetime
#
import re
#
from decimal import Decimal
#
from uuid import uuid4
#
from django.core import validators
#
from django.db import models
#
from django.test import TestCase
#
from django.utils.datastructures import SortedDict
#
from rest_framework import serializers
#
from tests.models import RESTFrameworkModel
class
TimestampedModel
(
models
.
Model
):
added
=
models
.
DateTimeField
(
auto_now_add
=
True
)
updated
=
models
.
DateTimeField
(
auto_now
=
True
)
#
class TimestampedModel(models.Model):
#
added = models.DateTimeField(auto_now_add=True)
#
updated = models.DateTimeField(auto_now=True)
class
CharPrimaryKeyModel
(
models
.
Model
):
id
=
models
.
CharField
(
max_length
=
20
,
primary_key
=
True
)
#
class CharPrimaryKeyModel(models.Model):
#
id = models.CharField(max_length=20, primary_key=True)
class
TimestampedModelSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
TimestampedModel
#
class TimestampedModelSerializer(serializers.ModelSerializer):
#
class Meta:
#
model = TimestampedModel
class
CharPrimaryKeyModelSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
CharPrimaryKeyModel
#
class CharPrimaryKeyModelSerializer(serializers.ModelSerializer):
#
class Meta:
#
model = CharPrimaryKeyModel
class
TimeFieldModel
(
models
.
Model
):
clock
=
models
.
TimeField
()
#
class TimeFieldModel(models.Model):
#
clock = models.TimeField()
class
TimeFieldModelSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
TimeFieldModel
#
class TimeFieldModelSerializer(serializers.ModelSerializer):
#
class Meta:
#
model = TimeFieldModel
SAMPLE_CHOICES
=
[
(
'red'
,
'Red'
),
(
'green'
,
'Green'
),
(
'blue'
,
'Blue'
),
]
#
SAMPLE_CHOICES = [
#
('red', 'Red'),
#
('green', 'Green'),
#
('blue', 'Blue'),
#
]
class
ChoiceFieldModel
(
models
.
Model
):
choice
=
models
.
CharField
(
choices
=
SAMPLE_CHOICES
,
blank
=
True
,
max_length
=
255
)
#
class ChoiceFieldModel(models.Model):
#
choice = models.CharField(choices=SAMPLE_CHOICES, blank=True, max_length=255)
class
ChoiceFieldModelSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
ChoiceFieldModel
class
ChoiceFieldModelWithNull
(
models
.
Model
):
choice
=
models
.
CharField
(
choices
=
SAMPLE_CHOICES
,
blank
=
True
,
null
=
True
,
max_length
=
255
)
class
ChoiceFieldModelWithNullSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
ChoiceFieldModelWithNull
class
BasicFieldTests
(
TestCase
):
def
test_auto_now_fields_read_only
(
self
):
"""
auto_now and auto_now_add fields should be read_only by default.
"""
serializer
=
TimestampedModelSerializer
()
self
.
assertEqual
(
serializer
.
fields
[
'added'
]
.
read_only
,
True
)
def
test_auto_pk_fields_read_only
(
self
):
"""
AutoField fields should be read_only by default.
"""
serializer
=
TimestampedModelSerializer
()
self
.
assertEqual
(
serializer
.
fields
[
'id'
]
.
read_only
,
True
)
def
test_non_auto_pk_fields_not_read_only
(
self
):
"""
PK fields other than AutoField fields should not be read_only by default.
"""
serializer
=
CharPrimaryKeyModelSerializer
()
self
.
assertEqual
(
serializer
.
fields
[
'id'
]
.
read_only
,
False
)
def
test_dict_field_ordering
(
self
):
"""
Field should preserve dictionary ordering, if it exists.
See: https://github.com/tomchristie/django-rest-framework/issues/832
"""
ret
=
SortedDict
()
ret
[
'c'
]
=
1
ret
[
'b'
]
=
1
ret
[
'a'
]
=
1
ret
[
'z'
]
=
1
field
=
serializers
.
Field
()
keys
=
list
(
field
.
to_native
(
ret
)
.
keys
())
self
.
assertEqual
(
keys
,
[
'c'
,
'b'
,
'a'
,
'z'
])
def
test_widget_html_attributes
(
self
):
"""
Make sure widget_html() renders the correct attributes
"""
r
=
re
.
compile
(
'(
\
S+)=["
\'
]?((?:.(?!["
\'
]?
\
s+(?:
\
S+)=|[>"
\'
]))+.)["
\'
]?'
)
form
=
TimeFieldModelSerializer
()
.
data
attributes
=
r
.
findall
(
form
.
fields
[
'clock'
]
.
widget_html
())
self
.
assertIn
((
'name'
,
'clock'
),
attributes
)
self
.
assertIn
((
'id'
,
'clock'
),
attributes
)
#
class ChoiceFieldModelSerializer(serializers.ModelSerializer):
#
class Meta:
#
model = ChoiceFieldModel
#
class ChoiceFieldModelWithNull(models.Model):
#
choice = models.CharField(choices=SAMPLE_CHOICES, blank=True, null=True, max_length=255)
#
class ChoiceFieldModelWithNullSerializer(serializers.ModelSerializer):
#
class Meta:
#
model = ChoiceFieldModelWithNull
#
class BasicFieldTests(TestCase):
#
def test_auto_now_fields_read_only(self):
#
"""
#
auto_now and auto_now_add fields should be read_only by default.
#
"""
#
serializer = TimestampedModelSerializer()
#
self.assertEqual(serializer.fields['added'].read_only, True)
#
def test_auto_pk_fields_read_only(self):
#
"""
#
AutoField fields should be read_only by default.
#
"""
#
serializer = TimestampedModelSerializer()
#
self.assertEqual(serializer.fields['id'].read_only, True)
#
def test_non_auto_pk_fields_not_read_only(self):
#
"""
#
PK fields other than AutoField fields should not be read_only by default.
#
"""
#
serializer = CharPrimaryKeyModelSerializer()
#
self.assertEqual(serializer.fields['id'].read_only, False)
#
def test_dict_field_ordering(self):
#
"""
#
Field should preserve dictionary ordering, if it exists.
#
See: https://github.com/tomchristie/django-rest-framework/issues/832
#
"""
#
ret = SortedDict()
#
ret['c'] = 1
#
ret['b'] = 1
#
ret['a'] = 1
#
ret['z'] = 1
#
field = serializers.Field()
#
keys = list(field.to_native(ret).keys())
#
self.assertEqual(keys, ['c', 'b', 'a', 'z'])
#
def test_widget_html_attributes(self):
#
"""
#
Make sure widget_html() renders the correct attributes
#
"""
#
r = re.compile('(\S+)=["\']?((?:.(?!["\']?\s+(?:\S+)=|[>"\']))+.)["\']?')
#
form = TimeFieldModelSerializer().data
#
attributes = r.findall(form.fields['clock'].widget_html())
#
self.assertIn(('name', 'clock'), attributes)
#
self.assertIn(('id', 'clock'), attributes)
class
DateFieldTest
(
TestCase
):
"""
Tests for the DateFieldTest from_native() and to_native() behavior
"""
def
test_from_native_string
(
self
):
"""
Make sure from_native() accepts default iso input formats.
"""
f
=
serializers
.
DateField
()
result_1
=
f
.
from_native
(
'1984-07-31'
)
self
.
assertEqual
(
datetime
.
date
(
1984
,
7
,
31
),
result_1
)
def
test_from_native_datetime_date
(
self
):
"""
Make sure from_native() accepts a datetime.date instance.
"""
f
=
serializers
.
DateField
()
result_1
=
f
.
from_native
(
datetime
.
date
(
1984
,
7
,
31
))
self
.
assertEqual
(
result_1
,
datetime
.
date
(
1984
,
7
,
31
))
def
test_from_native_custom_format
(
self
):
"""
Make sure from_native() accepts custom input formats.
"""
f
=
serializers
.
DateField
(
input_formats
=
[
'
%
Y --
%
d'
])
result
=
f
.
from_native
(
'1984 -- 31'
)
self
.
assertEqual
(
datetime
.
date
(
1984
,
1
,
31
),
result
)
def
test_from_native_invalid_default_on_custom_format
(
self
):
"""
Make sure from_native() don't accept default formats if custom format is preset
"""
f
=
serializers
.
DateField
(
input_formats
=
[
'
%
Y --
%
d'
])
try
:
f
.
from_native
(
'1984-07-31'
)
except
validators
.
ValidationError
as
e
:
self
.
assertEqual
(
e
.
messages
,
[
"Date has wrong format. Use one of these formats instead: YYYY -- DD"
])
else
:
self
.
fail
(
"ValidationError was not properly raised"
)
def
test_from_native_empty
(
self
):
"""
Make sure from_native() returns None on empty param.
"""
f
=
serializers
.
DateField
()
result
=
f
.
from_native
(
''
)
self
.
assertEqual
(
result
,
None
)
def
test_from_native_none
(
self
):
"""
Make sure from_native() returns None on None param.
"""
f
=
serializers
.
DateField
()
result
=
f
.
from_native
(
None
)
self
.
assertEqual
(
result
,
None
)
def
test_from_native_invalid_date
(
self
):
"""
Make sure from_native() raises a ValidationError on passing an invalid date.
"""
f
=
serializers
.
DateField
()
try
:
f
.
from_native
(
'1984-13-31'
)
except
validators
.
ValidationError
as
e
:
self
.
assertEqual
(
e
.
messages
,
[
"Date has wrong format. Use one of these formats instead: YYYY[-MM[-DD]]"
])
else
:
self
.
fail
(
"ValidationError was not properly raised"
)
def
test_from_native_invalid_format
(
self
):
"""
Make sure from_native() raises a ValidationError on passing an invalid format.
"""
f
=
serializers
.
DateField
()
try
:
f
.
from_native
(
'1984 -- 31'
)
except
validators
.
ValidationError
as
e
:
self
.
assertEqual
(
e
.
messages
,
[
"Date has wrong format. Use one of these formats instead: YYYY[-MM[-DD]]"
])
else
:
self
.
fail
(
"ValidationError was not properly raised"
)
def
test_to_native
(
self
):
"""
Make sure to_native() returns datetime as default.
"""
f
=
serializers
.
DateField
()
result_1
=
f
.
to_native
(
datetime
.
date
(
1984
,
7
,
31
))
self
.
assertEqual
(
datetime
.
date
(
1984
,
7
,
31
),
result_1
)
def
test_to_native_iso
(
self
):
"""
Make sure to_native() with 'iso-8601' returns iso formated date.
"""
f
=
serializers
.
DateField
(
format
=
'iso-8601'
)
result_1
=
f
.
to_native
(
datetime
.
date
(
1984
,
7
,
31
))
self
.
assertEqual
(
'1984-07-31'
,
result_1
)
def
test_to_native_custom_format
(
self
):
"""
Make sure to_native() returns correct custom format.
"""
f
=
serializers
.
DateField
(
format
=
"
%
Y -
%
m.
%
d"
)
result_1
=
f
.
to_native
(
datetime
.
date
(
1984
,
7
,
31
))
self
.
assertEqual
(
'1984 - 07.31'
,
result_1
)
def
test_to_native_none
(
self
):
"""
Make sure from_native() returns None on None param.
"""
f
=
serializers
.
DateField
(
required
=
False
)
self
.
assertEqual
(
None
,
f
.
to_native
(
None
))
class
DateTimeFieldTest
(
TestCase
):
"""
Tests for the DateTimeField from_native() and to_native() behavior
"""
def
test_from_native_string
(
self
):
"""
Make sure from_native() accepts default iso input formats.
"""
f
=
serializers
.
DateTimeField
()
result_1
=
f
.
from_native
(
'1984-07-31 04:31'
)
result_2
=
f
.
from_native
(
'1984-07-31 04:31:59'
)
result_3
=
f
.
from_native
(
'1984-07-31 04:31:59.000200'
)
self
.
assertEqual
(
datetime
.
datetime
(
1984
,
7
,
31
,
4
,
31
),
result_1
)
self
.
assertEqual
(
datetime
.
datetime
(
1984
,
7
,
31
,
4
,
31
,
59
),
result_2
)
self
.
assertEqual
(
datetime
.
datetime
(
1984
,
7
,
31
,
4
,
31
,
59
,
200
),
result_3
)
def
test_from_native_datetime_datetime
(
self
):
"""
Make sure from_native() accepts a datetime.datetime instance.
"""
f
=
serializers
.
DateTimeField
()
result_1
=
f
.
from_native
(
datetime
.
datetime
(
1984
,
7
,
31
,
4
,
31
))
result_2
=
f
.
from_native
(
datetime
.
datetime
(
1984
,
7
,
31
,
4
,
31
,
59
))
result_3
=
f
.
from_native
(
datetime
.
datetime
(
1984
,
7
,
31
,
4
,
31
,
59
,
200
))
self
.
assertEqual
(
result_1
,
datetime
.
datetime
(
1984
,
7
,
31
,
4
,
31
))
self
.
assertEqual
(
result_2
,
datetime
.
datetime
(
1984
,
7
,
31
,
4
,
31
,
59
))
self
.
assertEqual
(
result_3
,
datetime
.
datetime
(
1984
,
7
,
31
,
4
,
31
,
59
,
200
))
def
test_from_native_custom_format
(
self
):
"""
Make sure from_native() accepts custom input formats.
"""
f
=
serializers
.
DateTimeField
(
input_formats
=
[
'
%
Y --
%
H:
%
M'
])
result
=
f
.
from_native
(
'1984 -- 04:59'
)
self
.
assertEqual
(
datetime
.
datetime
(
1984
,
1
,
1
,
4
,
59
),
result
)
def
test_from_native_invalid_default_on_custom_format
(
self
):
"""
Make sure from_native() don't accept default formats if custom format is preset
"""
f
=
serializers
.
DateTimeField
(
input_formats
=
[
'
%
Y --
%
H:
%
M'
])
try
:
f
.
from_native
(
'1984-07-31 04:31:59'
)
except
validators
.
ValidationError
as
e
:
self
.
assertEqual
(
e
.
messages
,
[
"Datetime has wrong format. Use one of these formats instead: YYYY -- hh:mm"
])
else
:
self
.
fail
(
"ValidationError was not properly raised"
)
def
test_from_native_empty
(
self
):
"""
Make sure from_native() returns None on empty param.
"""
f
=
serializers
.
DateTimeField
()
result
=
f
.
from_native
(
''
)
self
.
assertEqual
(
result
,
None
)
def
test_from_native_none
(
self
):
"""
Make sure from_native() returns None on None param.
"""
f
=
serializers
.
DateTimeField
()
result
=
f
.
from_native
(
None
)
self
.
assertEqual
(
result
,
None
)
def
test_from_native_invalid_datetime
(
self
):
"""
Make sure from_native() raises a ValidationError on passing an invalid datetime.
"""
f
=
serializers
.
DateTimeField
()
try
:
f
.
from_native
(
'04:61:59'
)
except
validators
.
ValidationError
as
e
:
self
.
assertEqual
(
e
.
messages
,
[
"Datetime has wrong format. Use one of these formats instead: "
"YYYY-MM-DDThh:mm[:ss[.uuuuuu]][+HH:MM|-HH:MM|Z]"
])
else
:
self
.
fail
(
"ValidationError was not properly raised"
)
def
test_from_native_invalid_format
(
self
):
"""
Make sure from_native() raises a ValidationError on passing an invalid format.
"""
f
=
serializers
.
DateTimeField
()
try
:
f
.
from_native
(
'04 -- 31'
)
except
validators
.
ValidationError
as
e
:
self
.
assertEqual
(
e
.
messages
,
[
"Datetime has wrong format. Use one of these formats instead: "
"YYYY-MM-DDThh:mm[:ss[.uuuuuu]][+HH:MM|-HH:MM|Z]"
])
else
:
self
.
fail
(
"ValidationError was not properly raised"
)
def
test_to_native
(
self
):
"""
Make sure to_native() returns isoformat as default.
"""
f
=
serializers
.
DateTimeField
()
result_1
=
f
.
to_native
(
datetime
.
datetime
(
1984
,
7
,
31
))
result_2
=
f
.
to_native
(
datetime
.
datetime
(
1984
,
7
,
31
,
4
,
31
))
result_3
=
f
.
to_native
(
datetime
.
datetime
(
1984
,
7
,
31
,
4
,
31
,
59
))
result_4
=
f
.
to_native
(
datetime
.
datetime
(
1984
,
7
,
31
,
4
,
31
,
59
,
200
))
self
.
assertEqual
(
datetime
.
datetime
(
1984
,
7
,
31
),
result_1
)
self
.
assertEqual
(
datetime
.
datetime
(
1984
,
7
,
31
,
4
,
31
),
result_2
)
self
.
assertEqual
(
datetime
.
datetime
(
1984
,
7
,
31
,
4
,
31
,
59
),
result_3
)
self
.
assertEqual
(
datetime
.
datetime
(
1984
,
7
,
31
,
4
,
31
,
59
,
200
),
result_4
)
def
test_to_native_iso
(
self
):
"""
Make sure to_native() with format=iso-8601 returns iso formatted datetime.
"""
f
=
serializers
.
DateTimeField
(
format
=
'iso-8601'
)
result_1
=
f
.
to_native
(
datetime
.
datetime
(
1984
,
7
,
31
))
result_2
=
f
.
to_native
(
datetime
.
datetime
(
1984
,
7
,
31
,
4
,
31
))
result_3
=
f
.
to_native
(
datetime
.
datetime
(
1984
,
7
,
31
,
4
,
31
,
59
))
result_4
=
f
.
to_native
(
datetime
.
datetime
(
1984
,
7
,
31
,
4
,
31
,
59
,
200
))
self
.
assertEqual
(
'1984-07-31T00:00:00'
,
result_1
)
self
.
assertEqual
(
'1984-07-31T04:31:00'
,
result_2
)
self
.
assertEqual
(
'1984-07-31T04:31:59'
,
result_3
)
self
.
assertEqual
(
'1984-07-31T04:31:59.000200'
,
result_4
)
def
test_to_native_custom_format
(
self
):
"""
Make sure to_native() returns correct custom format.
"""
f
=
serializers
.
DateTimeField
(
format
=
"
%
Y -
%
H:
%
M"
)
result_1
=
f
.
to_native
(
datetime
.
datetime
(
1984
,
7
,
31
))
result_2
=
f
.
to_native
(
datetime
.
datetime
(
1984
,
7
,
31
,
4
,
31
))
result_3
=
f
.
to_native
(
datetime
.
datetime
(
1984
,
7
,
31
,
4
,
31
,
59
))
result_4
=
f
.
to_native
(
datetime
.
datetime
(
1984
,
7
,
31
,
4
,
31
,
59
,
200
))
self
.
assertEqual
(
'1984 - 00:00'
,
result_1
)
self
.
assertEqual
(
'1984 - 04:31'
,
result_2
)
self
.
assertEqual
(
'1984 - 04:31'
,
result_3
)
self
.
assertEqual
(
'1984 - 04:31'
,
result_4
)
def
test_to_native_none
(
self
):
"""
Make sure from_native() returns None on None param.
"""
f
=
serializers
.
DateTimeField
(
required
=
False
)
self
.
assertEqual
(
None
,
f
.
to_native
(
None
))
class
TimeFieldTest
(
TestCase
):
"""
Tests for the TimeField from_native() and to_native() behavior
"""
def
test_from_native_string
(
self
):
"""
Make sure from_native() accepts default iso input formats.
"""
f
=
serializers
.
TimeField
()
result_1
=
f
.
from_native
(
'04:31'
)
result_2
=
f
.
from_native
(
'04:31:59'
)
result_3
=
f
.
from_native
(
'04:31:59.000200'
)
self
.
assertEqual
(
datetime
.
time
(
4
,
31
),
result_1
)
self
.
assertEqual
(
datetime
.
time
(
4
,
31
,
59
),
result_2
)
self
.
assertEqual
(
datetime
.
time
(
4
,
31
,
59
,
200
),
result_3
)
def
test_from_native_datetime_time
(
self
):
"""
Make sure from_native() accepts a datetime.time instance.
"""
f
=
serializers
.
TimeField
()
result_1
=
f
.
from_native
(
datetime
.
time
(
4
,
31
))
result_2
=
f
.
from_native
(
datetime
.
time
(
4
,
31
,
59
))
result_3
=
f
.
from_native
(
datetime
.
time
(
4
,
31
,
59
,
200
))
self
.
assertEqual
(
result_1
,
datetime
.
time
(
4
,
31
))
self
.
assertEqual
(
result_2
,
datetime
.
time
(
4
,
31
,
59
))
self
.
assertEqual
(
result_3
,
datetime
.
time
(
4
,
31
,
59
,
200
))
def
test_from_native_custom_format
(
self
):
"""
Make sure from_native() accepts custom input formats.
"""
f
=
serializers
.
TimeField
(
input_formats
=
[
'
%
H --
%
M'
])
result
=
f
.
from_native
(
'04 -- 31'
)
self
.
assertEqual
(
datetime
.
time
(
4
,
31
),
result
)
def
test_from_native_invalid_default_on_custom_format
(
self
):
"""
Make sure from_native() don't accept default formats if custom format is preset
"""
f
=
serializers
.
TimeField
(
input_formats
=
[
'
%
H --
%
M'
])
try
:
f
.
from_native
(
'04:31:59'
)
except
validators
.
ValidationError
as
e
:
self
.
assertEqual
(
e
.
messages
,
[
"Time has wrong format. Use one of these formats instead: hh -- mm"
])
else
:
self
.
fail
(
"ValidationError was not properly raised"
)
def
test_from_native_empty
(
self
):
"""
Make sure from_native() returns None on empty param.
"""
f
=
serializers
.
TimeField
()
result
=
f
.
from_native
(
''
)
self
.
assertEqual
(
result
,
None
)
def
test_from_native_none
(
self
):
"""
Make sure from_native() returns None on None param.
"""
f
=
serializers
.
TimeField
()
result
=
f
.
from_native
(
None
)
self
.
assertEqual
(
result
,
None
)
def
test_from_native_invalid_time
(
self
):
"""
Make sure from_native() raises a ValidationError on passing an invalid time.
"""
f
=
serializers
.
TimeField
()
try
:
f
.
from_native
(
'04:61:59'
)
except
validators
.
ValidationError
as
e
:
self
.
assertEqual
(
e
.
messages
,
[
"Time has wrong format. Use one of these formats instead: "
"hh:mm[:ss[.uuuuuu]]"
])
else
:
self
.
fail
(
"ValidationError was not properly raised"
)
def
test_from_native_invalid_format
(
self
):
"""
Make sure from_native() raises a ValidationError on passing an invalid format.
"""
f
=
serializers
.
TimeField
()
try
:
f
.
from_native
(
'04 -- 31'
)
except
validators
.
ValidationError
as
e
:
self
.
assertEqual
(
e
.
messages
,
[
"Time has wrong format. Use one of these formats instead: "
"hh:mm[:ss[.uuuuuu]]"
])
else
:
self
.
fail
(
"ValidationError was not properly raised"
)
def
test_to_native
(
self
):
"""
Make sure to_native() returns time object as default.
"""
f
=
serializers
.
TimeField
()
result_1
=
f
.
to_native
(
datetime
.
time
(
4
,
31
))
result_2
=
f
.
to_native
(
datetime
.
time
(
4
,
31
,
59
))
result_3
=
f
.
to_native
(
datetime
.
time
(
4
,
31
,
59
,
200
))
self
.
assertEqual
(
datetime
.
time
(
4
,
31
),
result_1
)
self
.
assertEqual
(
datetime
.
time
(
4
,
31
,
59
),
result_2
)
self
.
assertEqual
(
datetime
.
time
(
4
,
31
,
59
,
200
),
result_3
)
def
test_to_native_iso
(
self
):
"""
Make sure to_native() with format='iso-8601' returns iso formatted time.
"""
f
=
serializers
.
TimeField
(
format
=
'iso-8601'
)
result_1
=
f
.
to_native
(
datetime
.
time
(
4
,
31
))
result_2
=
f
.
to_native
(
datetime
.
time
(
4
,
31
,
59
))
result_3
=
f
.
to_native
(
datetime
.
time
(
4
,
31
,
59
,
200
))
self
.
assertEqual
(
'04:31:00'
,
result_1
)
self
.
assertEqual
(
'04:31:59'
,
result_2
)
self
.
assertEqual
(
'04:31:59.000200'
,
result_3
)
def
test_to_native_custom_format
(
self
):
"""
Make sure to_native() returns correct custom format.
"""
f
=
serializers
.
TimeField
(
format
=
"
%
H -
%
S [
%
f]"
)
result_1
=
f
.
to_native
(
datetime
.
time
(
4
,
31
))
result_2
=
f
.
to_native
(
datetime
.
time
(
4
,
31
,
59
))
result_3
=
f
.
to_native
(
datetime
.
time
(
4
,
31
,
59
,
200
))
self
.
assertEqual
(
'04 - 00 [000000]'
,
result_1
)
self
.
assertEqual
(
'04 - 59 [000000]'
,
result_2
)
self
.
assertEqual
(
'04 - 59 [000200]'
,
result_3
)
class
DecimalFieldTest
(
TestCase
):
"""
Tests for the DecimalField from_native() and to_native() behavior
"""
def
test_from_native_string
(
self
):
"""
Make sure from_native() accepts string values
"""
f
=
serializers
.
DecimalField
()
result_1
=
f
.
from_native
(
'9000'
)
result_2
=
f
.
from_native
(
'1.00000001'
)
self
.
assertEqual
(
Decimal
(
'9000'
),
result_1
)
self
.
assertEqual
(
Decimal
(
'1.00000001'
),
result_2
)
def
test_from_native_invalid_string
(
self
):
"""
Make sure from_native() raises ValidationError on passing invalid string
"""
f
=
serializers
.
DecimalField
()
try
:
f
.
from_native
(
'123.45.6'
)
except
validators
.
ValidationError
as
e
:
self
.
assertEqual
(
e
.
messages
,
[
"Enter a number."
])
else
:
self
.
fail
(
"ValidationError was not properly raised"
)
def
test_from_native_integer
(
self
):
"""
Make sure from_native() accepts integer values
"""
f
=
serializers
.
DecimalField
()
result
=
f
.
from_native
(
9000
)
self
.
assertEqual
(
Decimal
(
'9000'
),
result
)
def
test_from_native_float
(
self
):
"""
Make sure from_native() accepts float values
"""
f
=
serializers
.
DecimalField
()
result
=
f
.
from_native
(
1.00000001
)
self
.
assertEqual
(
Decimal
(
'1.00000001'
),
result
)
def
test_from_native_empty
(
self
):
"""
Make sure from_native() returns None on empty param.
"""
f
=
serializers
.
DecimalField
()
result
=
f
.
from_native
(
''
)
self
.
assertEqual
(
result
,
None
)
def
test_from_native_none
(
self
):
"""
Make sure from_native() returns None on None param.
"""
f
=
serializers
.
DecimalField
()
result
=
f
.
from_native
(
None
)
self
.
assertEqual
(
result
,
None
)
def
test_to_native
(
self
):
"""
Make sure to_native() returns Decimal as string.
"""
f
=
serializers
.
DecimalField
()
result_1
=
f
.
to_native
(
Decimal
(
'9000'
))
result_2
=
f
.
to_native
(
Decimal
(
'1.00000001'
))
self
.
assertEqual
(
Decimal
(
'9000'
),
result_1
)
self
.
assertEqual
(
Decimal
(
'1.00000001'
),
result_2
)
def
test_to_native_none
(
self
):
"""
Make sure from_native() returns None on None param.
"""
f
=
serializers
.
DecimalField
(
required
=
False
)
self
.
assertEqual
(
None
,
f
.
to_native
(
None
))
def
test_valid_serialization
(
self
):
"""
Make sure the serializer works correctly
"""
class
DecimalSerializer
(
serializers
.
Serializer
):
decimal_field
=
serializers
.
DecimalField
(
max_value
=
9010
,
min_value
=
9000
,
max_digits
=
6
,
decimal_places
=
2
)
self
.
assertTrue
(
DecimalSerializer
(
data
=
{
'decimal_field'
:
'9001'
})
.
is_valid
())
self
.
assertTrue
(
DecimalSerializer
(
data
=
{
'decimal_field'
:
'9001.2'
})
.
is_valid
())
self
.
assertTrue
(
DecimalSerializer
(
data
=
{
'decimal_field'
:
'9001.23'
})
.
is_valid
())
self
.
assertFalse
(
DecimalSerializer
(
data
=
{
'decimal_field'
:
'8000'
})
.
is_valid
())
self
.
assertFalse
(
DecimalSerializer
(
data
=
{
'decimal_field'
:
'9900'
})
.
is_valid
())
self
.
assertFalse
(
DecimalSerializer
(
data
=
{
'decimal_field'
:
'9001.234'
})
.
is_valid
())
def
test_raise_max_value
(
self
):
"""
Make sure max_value violations raises ValidationError
"""
class
DecimalSerializer
(
serializers
.
Serializer
):
decimal_field
=
serializers
.
DecimalField
(
max_value
=
100
)
s
=
DecimalSerializer
(
data
=
{
'decimal_field'
:
'123'
})
self
.
assertFalse
(
s
.
is_valid
())
self
.
assertEqual
(
s
.
errors
,
{
'decimal_field'
:
[
'Ensure this value is less than or equal to 100.'
]})
def
test_raise_min_value
(
self
):
"""
Make sure min_value violations raises ValidationError
"""
class
DecimalSerializer
(
serializers
.
Serializer
):
decimal_field
=
serializers
.
DecimalField
(
min_value
=
100
)
s
=
DecimalSerializer
(
data
=
{
'decimal_field'
:
'99'
})
self
.
assertFalse
(
s
.
is_valid
())
self
.
assertEqual
(
s
.
errors
,
{
'decimal_field'
:
[
'Ensure this value is greater than or equal to 100.'
]})
def
test_raise_max_digits
(
self
):
"""
Make sure max_digits violations raises ValidationError
"""
class
DecimalSerializer
(
serializers
.
Serializer
):
decimal_field
=
serializers
.
DecimalField
(
max_digits
=
5
)
s
=
DecimalSerializer
(
data
=
{
'decimal_field'
:
'123.456'
})
self
.
assertFalse
(
s
.
is_valid
())
self
.
assertEqual
(
s
.
errors
,
{
'decimal_field'
:
[
'Ensure that there are no more than 5 digits in total.'
]})
def
test_raise_max_decimal_places
(
self
):
"""
Make sure max_decimal_places violations raises ValidationError
"""
class
DecimalSerializer
(
serializers
.
Serializer
):
decimal_field
=
serializers
.
DecimalField
(
decimal_places
=
3
)
s
=
DecimalSerializer
(
data
=
{
'decimal_field'
:
'123.4567'
})
self
.
assertFalse
(
s
.
is_valid
())
self
.
assertEqual
(
s
.
errors
,
{
'decimal_field'
:
[
'Ensure that there are no more than 3 decimal places.'
]})
def
test_raise_max_whole_digits
(
self
):
"""
Make sure max_whole_digits violations raises ValidationError
"""
class
DecimalSerializer
(
serializers
.
Serializer
):
decimal_field
=
serializers
.
DecimalField
(
max_digits
=
4
,
decimal_places
=
3
)
s
=
DecimalSerializer
(
data
=
{
'decimal_field'
:
'12345.6'
})
self
.
assertFalse
(
s
.
is_valid
())
self
.
assertEqual
(
s
.
errors
,
{
'decimal_field'
:
[
'Ensure that there are no more than 4 digits in total.'
]})
class
ChoiceFieldTests
(
TestCase
):
"""
Tests for the ChoiceField options generator
"""
def
test_choices_required
(
self
):
"""
Make sure proper choices are rendered if field is required
"""
f
=
serializers
.
ChoiceField
(
required
=
True
,
choices
=
SAMPLE_CHOICES
)
self
.
assertEqual
(
f
.
choices
,
SAMPLE_CHOICES
)
def
test_choices_not_required
(
self
):
"""
Make sure proper choices (plus blank) are rendered if the field isn't required
"""
f
=
serializers
.
ChoiceField
(
required
=
False
,
choices
=
SAMPLE_CHOICES
)
self
.
assertEqual
(
f
.
choices
,
models
.
fields
.
BLANK_CHOICE_DASH
+
SAMPLE_CHOICES
)
def
test_blank_choice_display
(
self
):
blank
=
'No Preference'
f
=
serializers
.
ChoiceField
(
required
=
False
,
choices
=
SAMPLE_CHOICES
,
blank_display_value
=
blank
,
)
self
.
assertEqual
(
f
.
choices
,
[(
''
,
blank
)]
+
SAMPLE_CHOICES
)
def
test_invalid_choice_model
(
self
):
s
=
ChoiceFieldModelSerializer
(
data
=
{
'choice'
:
'wrong_value'
})
self
.
assertFalse
(
s
.
is_valid
())
self
.
assertEqual
(
s
.
errors
,
{
'choice'
:
[
'Select a valid choice. wrong_value is not one of the available choices.'
]})
self
.
assertEqual
(
s
.
data
[
'choice'
],
''
)
def
test_empty_choice_model
(
self
):
"""
Test that the 'empty' value is correctly passed and used depending on
the 'null' property on the model field.
"""
s
=
ChoiceFieldModelSerializer
(
data
=
{
'choice'
:
''
})
self
.
assertTrue
(
s
.
is_valid
())
self
.
assertEqual
(
s
.
data
[
'choice'
],
''
)
s
=
ChoiceFieldModelWithNullSerializer
(
data
=
{
'choice'
:
''
})
self
.
assertTrue
(
s
.
is_valid
())
self
.
assertEqual
(
s
.
data
[
'choice'
],
None
)
def
test_from_native_empty
(
self
):
"""
Make sure from_native() returns an empty string on empty param by default.
"""
f
=
serializers
.
ChoiceField
(
choices
=
SAMPLE_CHOICES
)
self
.
assertEqual
(
f
.
from_native
(
''
),
''
)
self
.
assertEqual
(
f
.
from_native
(
None
),
''
)
def
test_from_native_empty_override
(
self
):
"""
Make sure you can override from_native() behavior regarding empty values.
"""
f
=
serializers
.
ChoiceField
(
choices
=
SAMPLE_CHOICES
,
empty
=
None
)
self
.
assertEqual
(
f
.
from_native
(
''
),
None
)
self
.
assertEqual
(
f
.
from_native
(
None
),
None
)
def
test_metadata_choices
(
self
):
"""
Make sure proper choices are included in the field's metadata.
"""
choices
=
[{
'value'
:
v
,
'display_name'
:
n
}
for
v
,
n
in
SAMPLE_CHOICES
]
f
=
serializers
.
ChoiceField
(
choices
=
SAMPLE_CHOICES
)
self
.
assertEqual
(
f
.
metadata
()[
'choices'
],
choices
)
def
test_metadata_choices_not_required
(
self
):
"""
Make sure proper choices are included in the field's metadata.
"""
choices
=
[{
'value'
:
v
,
'display_name'
:
n
}
for
v
,
n
in
models
.
fields
.
BLANK_CHOICE_DASH
+
SAMPLE_CHOICES
]
f
=
serializers
.
ChoiceField
(
required
=
False
,
choices
=
SAMPLE_CHOICES
)
self
.
assertEqual
(
f
.
metadata
()[
'choices'
],
choices
)
class
EmailFieldTests
(
TestCase
):
"""
Tests for EmailField attribute values
"""
class
EmailFieldModel
(
RESTFrameworkModel
):
email_field
=
models
.
EmailField
(
blank
=
True
)
class
EmailFieldWithGivenMaxLengthModel
(
RESTFrameworkModel
):
email_field
=
models
.
EmailField
(
max_length
=
150
,
blank
=
True
)
def
test_default_model_value
(
self
):
class
EmailFieldSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
self
.
EmailFieldModel
serializer
=
EmailFieldSerializer
(
data
=
{})
self
.
assertEqual
(
serializer
.
is_valid
(),
True
)
self
.
assertEqual
(
getattr
(
serializer
.
fields
[
'email_field'
],
'max_length'
),
75
)
def
test_given_model_value
(
self
):
class
EmailFieldSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
self
.
EmailFieldWithGivenMaxLengthModel
serializer
=
EmailFieldSerializer
(
data
=
{})
self
.
assertEqual
(
serializer
.
is_valid
(),
True
)
self
.
assertEqual
(
getattr
(
serializer
.
fields
[
'email_field'
],
'max_length'
),
150
)
def
test_given_serializer_value
(
self
):
class
EmailFieldSerializer
(
serializers
.
ModelSerializer
):
email_field
=
serializers
.
EmailField
(
source
=
'email_field'
,
max_length
=
20
,
required
=
False
)
class
Meta
:
model
=
self
.
EmailFieldModel
serializer
=
EmailFieldSerializer
(
data
=
{})
self
.
assertEqual
(
serializer
.
is_valid
(),
True
)
self
.
assertEqual
(
getattr
(
serializer
.
fields
[
'email_field'
],
'max_length'
),
20
)
class
SlugFieldTests
(
TestCase
):
"""
Tests for SlugField attribute values
"""
class
SlugFieldModel
(
RESTFrameworkModel
):
slug_field
=
models
.
SlugField
(
blank
=
True
)
class
SlugFieldWithGivenMaxLengthModel
(
RESTFrameworkModel
):
slug_field
=
models
.
SlugField
(
max_length
=
84
,
blank
=
True
)
def
test_default_model_value
(
self
):
class
SlugFieldSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
self
.
SlugFieldModel
serializer
=
SlugFieldSerializer
(
data
=
{})
self
.
assertEqual
(
serializer
.
is_valid
(),
True
)
self
.
assertEqual
(
getattr
(
serializer
.
fields
[
'slug_field'
],
'max_length'
),
50
)
def
test_given_model_value
(
self
):
class
SlugFieldSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
self
.
SlugFieldWithGivenMaxLengthModel
serializer
=
SlugFieldSerializer
(
data
=
{})
self
.
assertEqual
(
serializer
.
is_valid
(),
True
)
self
.
assertEqual
(
getattr
(
serializer
.
fields
[
'slug_field'
],
'max_length'
),
84
)
def
test_given_serializer_value
(
self
):
class
SlugFieldSerializer
(
serializers
.
ModelSerializer
):
slug_field
=
serializers
.
SlugField
(
source
=
'slug_field'
,
max_length
=
20
,
required
=
False
)
class
Meta
:
model
=
self
.
SlugFieldModel
serializer
=
SlugFieldSerializer
(
data
=
{})
self
.
assertEqual
(
serializer
.
is_valid
(),
True
)
self
.
assertEqual
(
getattr
(
serializer
.
fields
[
'slug_field'
],
'max_length'
),
20
)
def
test_invalid_slug
(
self
):
"""
Make sure an invalid slug raises ValidationError
"""
class
SlugFieldSerializer
(
serializers
.
ModelSerializer
):
slug_field
=
serializers
.
SlugField
(
source
=
'slug_field'
,
max_length
=
20
,
required
=
True
)
#
class DateFieldTest(TestCase):
#
"""
#
Tests for the DateFieldTest from_native() and to_native() behavior
#
"""
#
def test_from_native_string(self):
#
"""
#
Make sure from_native() accepts default iso input formats.
#
"""
#
f = serializers.DateField()
#
result_1 = f.from_native('1984-07-31')
#
self.assertEqual(datetime.date(1984, 7, 31), result_1)
#
def test_from_native_datetime_date(self):
#
"""
#
Make sure from_native() accepts a datetime.date instance.
#
"""
#
f = serializers.DateField()
#
result_1 = f.from_native(datetime.date(1984, 7, 31))
#
self.assertEqual(result_1, datetime.date(1984, 7, 31))
#
def test_from_native_custom_format(self):
#
"""
#
Make sure from_native() accepts custom input formats.
#
"""
#
f = serializers.DateField(input_formats=['%Y -- %d'])
#
result = f.from_native('1984 -- 31')
#
self.assertEqual(datetime.date(1984, 1, 31), result)
#
def test_from_native_invalid_default_on_custom_format(self):
#
"""
#
Make sure from_native() don't accept default formats if custom format is preset
#
"""
#
f = serializers.DateField(input_formats=['%Y -- %d'])
#
try:
#
f.from_native('1984-07-31')
#
except validators.ValidationError as e:
#
self.assertEqual(e.messages, ["Date has wrong format. Use one of these formats instead: YYYY -- DD"])
#
else:
#
self.fail("ValidationError was not properly raised")
#
def test_from_native_empty(self):
#
"""
#
Make sure from_native() returns None on empty param.
#
"""
#
f = serializers.DateField()
#
result = f.from_native('')
#
self.assertEqual(result, None)
#
def test_from_native_none(self):
#
"""
#
Make sure from_native() returns None on None param.
#
"""
#
f = serializers.DateField()
#
result = f.from_native(None)
#
self.assertEqual(result, None)
#
def test_from_native_invalid_date(self):
#
"""
#
Make sure from_native() raises a ValidationError on passing an invalid date.
#
"""
#
f = serializers.DateField()
#
try:
#
f.from_native('1984-13-31')
#
except validators.ValidationError as e:
#
self.assertEqual(e.messages, ["Date has wrong format. Use one of these formats instead: YYYY[-MM[-DD]]"])
#
else:
#
self.fail("ValidationError was not properly raised")
#
def test_from_native_invalid_format(self):
#
"""
#
Make sure from_native() raises a ValidationError on passing an invalid format.
#
"""
#
f = serializers.DateField()
#
try:
#
f.from_native('1984 -- 31')
#
except validators.ValidationError as e:
#
self.assertEqual(e.messages, ["Date has wrong format. Use one of these formats instead: YYYY[-MM[-DD]]"])
#
else:
#
self.fail("ValidationError was not properly raised")
#
def test_to_native(self):
#
"""
#
Make sure to_native() returns datetime as default.
#
"""
#
f = serializers.DateField()
#
result_1 = f.to_native(datetime.date(1984, 7, 31))
#
self.assertEqual(datetime.date(1984, 7, 31), result_1)
#
def test_to_native_iso(self):
#
"""
#
Make sure to_native() with 'iso-8601' returns iso formated date.
#
"""
#
f = serializers.DateField(format='iso-8601')
#
result_1 = f.to_native(datetime.date(1984, 7, 31))
#
self.assertEqual('1984-07-31', result_1)
#
def test_to_native_custom_format(self):
#
"""
#
Make sure to_native() returns correct custom format.
#
"""
#
f = serializers.DateField(format="%Y - %m.%d")
#
result_1 = f.to_native(datetime.date(1984, 7, 31))
#
self.assertEqual('1984 - 07.31', result_1)
#
def test_to_native_none(self):
#
"""
#
Make sure from_native() returns None on None param.
#
"""
#
f = serializers.DateField(required=False)
#
self.assertEqual(None, f.to_native(None))
#
class DateTimeFieldTest(TestCase):
#
"""
#
Tests for the DateTimeField from_native() and to_native() behavior
#
"""
#
def test_from_native_string(self):
#
"""
#
Make sure from_native() accepts default iso input formats.
#
"""
#
f = serializers.DateTimeField()
#
result_1 = f.from_native('1984-07-31 04:31')
#
result_2 = f.from_native('1984-07-31 04:31:59')
#
result_3 = f.from_native('1984-07-31 04:31:59.000200')
#
self.assertEqual(datetime.datetime(1984, 7, 31, 4, 31), result_1)
#
self.assertEqual(datetime.datetime(1984, 7, 31, 4, 31, 59), result_2)
#
self.assertEqual(datetime.datetime(1984, 7, 31, 4, 31, 59, 200), result_3)
#
def test_from_native_datetime_datetime(self):
#
"""
#
Make sure from_native() accepts a datetime.datetime instance.
#
"""
#
f = serializers.DateTimeField()
#
result_1 = f.from_native(datetime.datetime(1984, 7, 31, 4, 31))
#
result_2 = f.from_native(datetime.datetime(1984, 7, 31, 4, 31, 59))
#
result_3 = f.from_native(datetime.datetime(1984, 7, 31, 4, 31, 59, 200))
#
self.assertEqual(result_1, datetime.datetime(1984, 7, 31, 4, 31))
#
self.assertEqual(result_2, datetime.datetime(1984, 7, 31, 4, 31, 59))
#
self.assertEqual(result_3, datetime.datetime(1984, 7, 31, 4, 31, 59, 200))
#
def test_from_native_custom_format(self):
#
"""
#
Make sure from_native() accepts custom input formats.
#
"""
#
f = serializers.DateTimeField(input_formats=['%Y -- %H:%M'])
#
result = f.from_native('1984 -- 04:59')
#
self.assertEqual(datetime.datetime(1984, 1, 1, 4, 59), result)
#
def test_from_native_invalid_default_on_custom_format(self):
#
"""
#
Make sure from_native() don't accept default formats if custom format is preset
#
"""
#
f = serializers.DateTimeField(input_formats=['%Y -- %H:%M'])
#
try:
#
f.from_native('1984-07-31 04:31:59')
#
except validators.ValidationError as e:
#
self.assertEqual(e.messages, ["Datetime has wrong format. Use one of these formats instead: YYYY -- hh:mm"])
#
else:
#
self.fail("ValidationError was not properly raised")
#
def test_from_native_empty(self):
#
"""
#
Make sure from_native() returns None on empty param.
#
"""
#
f = serializers.DateTimeField()
#
result = f.from_native('')
#
self.assertEqual(result, None)
#
def test_from_native_none(self):
#
"""
#
Make sure from_native() returns None on None param.
#
"""
#
f = serializers.DateTimeField()
#
result = f.from_native(None)
#
self.assertEqual(result, None)
#
def test_from_native_invalid_datetime(self):
#
"""
#
Make sure from_native() raises a ValidationError on passing an invalid datetime.
#
"""
#
f = serializers.DateTimeField()
#
try:
#
f.from_native('04:61:59')
#
except validators.ValidationError as e:
#
self.assertEqual(e.messages, ["Datetime has wrong format. Use one of these formats instead: "
#
"YYYY-MM-DDThh:mm[:ss[.uuuuuu]][+HH:MM|-HH:MM|Z]"])
#
else:
#
self.fail("ValidationError was not properly raised")
#
def test_from_native_invalid_format(self):
#
"""
#
Make sure from_native() raises a ValidationError on passing an invalid format.
#
"""
#
f = serializers.DateTimeField()
#
try:
#
f.from_native('04 -- 31')
#
except validators.ValidationError as e:
#
self.assertEqual(e.messages, ["Datetime has wrong format. Use one of these formats instead: "
#
"YYYY-MM-DDThh:mm[:ss[.uuuuuu]][+HH:MM|-HH:MM|Z]"])
#
else:
#
self.fail("ValidationError was not properly raised")
#
def test_to_native(self):
#
"""
#
Make sure to_native() returns isoformat as default.
#
"""
#
f = serializers.DateTimeField()
#
result_1 = f.to_native(datetime.datetime(1984, 7, 31))
#
result_2 = f.to_native(datetime.datetime(1984, 7, 31, 4, 31))
#
result_3 = f.to_native(datetime.datetime(1984, 7, 31, 4, 31, 59))
#
result_4 = f.to_native(datetime.datetime(1984, 7, 31, 4, 31, 59, 200))
#
self.assertEqual(datetime.datetime(1984, 7, 31), result_1)
#
self.assertEqual(datetime.datetime(1984, 7, 31, 4, 31), result_2)
#
self.assertEqual(datetime.datetime(1984, 7, 31, 4, 31, 59), result_3)
#
self.assertEqual(datetime.datetime(1984, 7, 31, 4, 31, 59, 200), result_4)
#
def test_to_native_iso(self):
#
"""
#
Make sure to_native() with format=iso-8601 returns iso formatted datetime.
#
"""
#
f = serializers.DateTimeField(format='iso-8601')
#
result_1 = f.to_native(datetime.datetime(1984, 7, 31))
#
result_2 = f.to_native(datetime.datetime(1984, 7, 31, 4, 31))
#
result_3 = f.to_native(datetime.datetime(1984, 7, 31, 4, 31, 59))
#
result_4 = f.to_native(datetime.datetime(1984, 7, 31, 4, 31, 59, 200))
#
self.assertEqual('1984-07-31T00:00:00', result_1)
#
self.assertEqual('1984-07-31T04:31:00', result_2)
#
self.assertEqual('1984-07-31T04:31:59', result_3)
#
self.assertEqual('1984-07-31T04:31:59.000200', result_4)
#
def test_to_native_custom_format(self):
#
"""
#
Make sure to_native() returns correct custom format.
#
"""
#
f = serializers.DateTimeField(format="%Y - %H:%M")
#
result_1 = f.to_native(datetime.datetime(1984, 7, 31))
#
result_2 = f.to_native(datetime.datetime(1984, 7, 31, 4, 31))
#
result_3 = f.to_native(datetime.datetime(1984, 7, 31, 4, 31, 59))
#
result_4 = f.to_native(datetime.datetime(1984, 7, 31, 4, 31, 59, 200))
#
self.assertEqual('1984 - 00:00', result_1)
#
self.assertEqual('1984 - 04:31', result_2)
#
self.assertEqual('1984 - 04:31', result_3)
#
self.assertEqual('1984 - 04:31', result_4)
#
def test_to_native_none(self):
#
"""
#
Make sure from_native() returns None on None param.
#
"""
#
f = serializers.DateTimeField(required=False)
#
self.assertEqual(None, f.to_native(None))
#
class TimeFieldTest(TestCase):
#
"""
#
Tests for the TimeField from_native() and to_native() behavior
#
"""
#
def test_from_native_string(self):
#
"""
#
Make sure from_native() accepts default iso input formats.
#
"""
#
f = serializers.TimeField()
#
result_1 = f.from_native('04:31')
#
result_2 = f.from_native('04:31:59')
#
result_3 = f.from_native('04:31:59.000200')
#
self.assertEqual(datetime.time(4, 31), result_1)
#
self.assertEqual(datetime.time(4, 31, 59), result_2)
#
self.assertEqual(datetime.time(4, 31, 59, 200), result_3)
#
def test_from_native_datetime_time(self):
#
"""
#
Make sure from_native() accepts a datetime.time instance.
#
"""
#
f = serializers.TimeField()
#
result_1 = f.from_native(datetime.time(4, 31))
#
result_2 = f.from_native(datetime.time(4, 31, 59))
#
result_3 = f.from_native(datetime.time(4, 31, 59, 200))
#
self.assertEqual(result_1, datetime.time(4, 31))
#
self.assertEqual(result_2, datetime.time(4, 31, 59))
#
self.assertEqual(result_3, datetime.time(4, 31, 59, 200))
#
def test_from_native_custom_format(self):
#
"""
#
Make sure from_native() accepts custom input formats.
#
"""
#
f = serializers.TimeField(input_formats=['%H -- %M'])
#
result = f.from_native('04 -- 31')
#
self.assertEqual(datetime.time(4, 31), result)
#
def test_from_native_invalid_default_on_custom_format(self):
#
"""
#
Make sure from_native() don't accept default formats if custom format is preset
#
"""
#
f = serializers.TimeField(input_formats=['%H -- %M'])
#
try:
#
f.from_native('04:31:59')
#
except validators.ValidationError as e:
#
self.assertEqual(e.messages, ["Time has wrong format. Use one of these formats instead: hh -- mm"])
#
else:
#
self.fail("ValidationError was not properly raised")
#
def test_from_native_empty(self):
#
"""
#
Make sure from_native() returns None on empty param.
#
"""
#
f = serializers.TimeField()
#
result = f.from_native('')
#
self.assertEqual(result, None)
#
def test_from_native_none(self):
#
"""
#
Make sure from_native() returns None on None param.
#
"""
#
f = serializers.TimeField()
#
result = f.from_native(None)
#
self.assertEqual(result, None)
#
def test_from_native_invalid_time(self):
#
"""
#
Make sure from_native() raises a ValidationError on passing an invalid time.
#
"""
#
f = serializers.TimeField()
#
try:
#
f.from_native('04:61:59')
#
except validators.ValidationError as e:
#
self.assertEqual(e.messages, ["Time has wrong format. Use one of these formats instead: "
#
"hh:mm[:ss[.uuuuuu]]"])
#
else:
#
self.fail("ValidationError was not properly raised")
#
def test_from_native_invalid_format(self):
#
"""
#
Make sure from_native() raises a ValidationError on passing an invalid format.
#
"""
#
f = serializers.TimeField()
#
try:
#
f.from_native('04 -- 31')
#
except validators.ValidationError as e:
#
self.assertEqual(e.messages, ["Time has wrong format. Use one of these formats instead: "
#
"hh:mm[:ss[.uuuuuu]]"])
#
else:
#
self.fail("ValidationError was not properly raised")
#
def test_to_native(self):
#
"""
#
Make sure to_native() returns time object as default.
#
"""
#
f = serializers.TimeField()
#
result_1 = f.to_native(datetime.time(4, 31))
#
result_2 = f.to_native(datetime.time(4, 31, 59))
#
result_3 = f.to_native(datetime.time(4, 31, 59, 200))
#
self.assertEqual(datetime.time(4, 31), result_1)
#
self.assertEqual(datetime.time(4, 31, 59), result_2)
#
self.assertEqual(datetime.time(4, 31, 59, 200), result_3)
#
def test_to_native_iso(self):
#
"""
#
Make sure to_native() with format='iso-8601' returns iso formatted time.
#
"""
#
f = serializers.TimeField(format='iso-8601')
#
result_1 = f.to_native(datetime.time(4, 31))
#
result_2 = f.to_native(datetime.time(4, 31, 59))
#
result_3 = f.to_native(datetime.time(4, 31, 59, 200))
#
self.assertEqual('04:31:00', result_1)
#
self.assertEqual('04:31:59', result_2)
#
self.assertEqual('04:31:59.000200', result_3)
#
def test_to_native_custom_format(self):
#
"""
#
Make sure to_native() returns correct custom format.
#
"""
#
f = serializers.TimeField(format="%H - %S [%f]")
#
result_1 = f.to_native(datetime.time(4, 31))
#
result_2 = f.to_native(datetime.time(4, 31, 59))
#
result_3 = f.to_native(datetime.time(4, 31, 59, 200))
#
self.assertEqual('04 - 00 [000000]', result_1)
#
self.assertEqual('04 - 59 [000000]', result_2)
#
self.assertEqual('04 - 59 [000200]', result_3)
#
class DecimalFieldTest(TestCase):
#
"""
#
Tests for the DecimalField from_native() and to_native() behavior
#
"""
#
def test_from_native_string(self):
#
"""
#
Make sure from_native() accepts string values
#
"""
#
f = serializers.DecimalField()
#
result_1 = f.from_native('9000')
#
result_2 = f.from_native('1.00000001')
#
self.assertEqual(Decimal('9000'), result_1)
#
self.assertEqual(Decimal('1.00000001'), result_2)
#
def test_from_native_invalid_string(self):
#
"""
#
Make sure from_native() raises ValidationError on passing invalid string
#
"""
#
f = serializers.DecimalField()
#
try:
#
f.from_native('123.45.6')
#
except validators.ValidationError as e:
#
self.assertEqual(e.messages, ["Enter a number."])
#
else:
#
self.fail("ValidationError was not properly raised")
#
def test_from_native_integer(self):
#
"""
#
Make sure from_native() accepts integer values
#
"""
#
f = serializers.DecimalField()
#
result = f.from_native(9000)
#
self.assertEqual(Decimal('9000'), result)
#
def test_from_native_float(self):
#
"""
#
Make sure from_native() accepts float values
#
"""
#
f = serializers.DecimalField()
#
result = f.from_native(1.00000001)
#
self.assertEqual(Decimal('1.00000001'), result)
#
def test_from_native_empty(self):
#
"""
#
Make sure from_native() returns None on empty param.
#
"""
#
f = serializers.DecimalField()
#
result = f.from_native('')
#
self.assertEqual(result, None)
#
def test_from_native_none(self):
#
"""
#
Make sure from_native() returns None on None param.
#
"""
#
f = serializers.DecimalField()
#
result = f.from_native(None)
#
self.assertEqual(result, None)
#
def test_to_native(self):
#
"""
#
Make sure to_native() returns Decimal as string.
#
"""
#
f = serializers.DecimalField()
#
result_1 = f.to_native(Decimal('9000'))
#
result_2 = f.to_native(Decimal('1.00000001'))
#
self.assertEqual(Decimal('9000'), result_1)
#
self.assertEqual(Decimal('1.00000001'), result_2)
#
def test_to_native_none(self):
#
"""
#
Make sure from_native() returns None on None param.
#
"""
#
f = serializers.DecimalField(required=False)
#
self.assertEqual(None, f.to_native(None))
#
def test_valid_serialization(self):
#
"""
#
Make sure the serializer works correctly
#
"""
#
class DecimalSerializer(serializers.Serializer):
#
decimal_field = serializers.DecimalField(max_value=9010,
#
min_value=9000,
#
max_digits=6,
#
decimal_places=2)
#
self.assertTrue(DecimalSerializer(data={'decimal_field': '9001'}).is_valid())
#
self.assertTrue(DecimalSerializer(data={'decimal_field': '9001.2'}).is_valid())
#
self.assertTrue(DecimalSerializer(data={'decimal_field': '9001.23'}).is_valid())
#
self.assertFalse(DecimalSerializer(data={'decimal_field': '8000'}).is_valid())
#
self.assertFalse(DecimalSerializer(data={'decimal_field': '9900'}).is_valid())
#
self.assertFalse(DecimalSerializer(data={'decimal_field': '9001.234'}).is_valid())
#
def test_raise_max_value(self):
#
"""
#
Make sure max_value violations raises ValidationError
#
"""
#
class DecimalSerializer(serializers.Serializer):
#
decimal_field = serializers.DecimalField(max_value=100)
#
s = DecimalSerializer(data={'decimal_field': '123'})
#
self.assertFalse(s.is_valid())
#
self.assertEqual(s.errors, {'decimal_field': ['Ensure this value is less than or equal to 100.']})
#
def test_raise_min_value(self):
#
"""
#
Make sure min_value violations raises ValidationError
#
"""
#
class DecimalSerializer(serializers.Serializer):
#
decimal_field = serializers.DecimalField(min_value=100)
#
s = DecimalSerializer(data={'decimal_field': '99'})
#
self.assertFalse(s.is_valid())
#
self.assertEqual(s.errors, {'decimal_field': ['Ensure this value is greater than or equal to 100.']})
#
def test_raise_max_digits(self):
#
"""
#
Make sure max_digits violations raises ValidationError
#
"""
#
class DecimalSerializer(serializers.Serializer):
#
decimal_field = serializers.DecimalField(max_digits=5)
#
s = DecimalSerializer(data={'decimal_field': '123.456'})
#
self.assertFalse(s.is_valid())
#
self.assertEqual(s.errors, {'decimal_field': ['Ensure that there are no more than 5 digits in total.']})
#
def test_raise_max_decimal_places(self):
#
"""
#
Make sure max_decimal_places violations raises ValidationError
#
"""
#
class DecimalSerializer(serializers.Serializer):
#
decimal_field = serializers.DecimalField(decimal_places=3)
#
s = DecimalSerializer(data={'decimal_field': '123.4567'})
#
self.assertFalse(s.is_valid())
#
self.assertEqual(s.errors, {'decimal_field': ['Ensure that there are no more than 3 decimal places.']})
#
def test_raise_max_whole_digits(self):
#
"""
#
Make sure max_whole_digits violations raises ValidationError
#
"""
#
class DecimalSerializer(serializers.Serializer):
#
decimal_field = serializers.DecimalField(max_digits=4, decimal_places=3)
#
s = DecimalSerializer(data={'decimal_field': '12345.6'})
#
self.assertFalse(s.is_valid())
#
self.assertEqual(s.errors, {'decimal_field': ['Ensure that there are no more than 4 digits in total.']})
#
class ChoiceFieldTests(TestCase):
#
"""
#
Tests for the ChoiceField options generator
#
"""
#
def test_choices_required(self):
#
"""
#
Make sure proper choices are rendered if field is required
#
"""
#
f = serializers.ChoiceField(required=True, choices=SAMPLE_CHOICES)
#
self.assertEqual(f.choices, SAMPLE_CHOICES)
#
def test_choices_not_required(self):
#
"""
#
Make sure proper choices (plus blank) are rendered if the field isn't required
#
"""
#
f = serializers.ChoiceField(required=False, choices=SAMPLE_CHOICES)
#
self.assertEqual(f.choices, models.fields.BLANK_CHOICE_DASH + SAMPLE_CHOICES)
#
def test_blank_choice_display(self):
#
blank = 'No Preference'
#
f = serializers.ChoiceField(
#
required=False,
#
choices=SAMPLE_CHOICES,
#
blank_display_value=blank,
#
)
#
self.assertEqual(f.choices, [('', blank)] + SAMPLE_CHOICES)
#
def test_invalid_choice_model(self):
#
s = ChoiceFieldModelSerializer(data={'choice': 'wrong_value'})
#
self.assertFalse(s.is_valid())
#
self.assertEqual(s.errors, {'choice': ['Select a valid choice. wrong_value is not one of the available choices.']})
#
self.assertEqual(s.data['choice'], '')
#
def test_empty_choice_model(self):
#
"""
#
Test that the 'empty' value is correctly passed and used depending on
#
the 'null' property on the model field.
#
"""
#
s = ChoiceFieldModelSerializer(data={'choice': ''})
#
self.assertTrue(s.is_valid())
#
self.assertEqual(s.data['choice'], '')
#
s = ChoiceFieldModelWithNullSerializer(data={'choice': ''})
#
self.assertTrue(s.is_valid())
#
self.assertEqual(s.data['choice'], None)
#
def test_from_native_empty(self):
#
"""
#
Make sure from_native() returns an empty string on empty param by default.
#
"""
#
f = serializers.ChoiceField(choices=SAMPLE_CHOICES)
#
self.assertEqual(f.from_native(''), '')
#
self.assertEqual(f.from_native(None), '')
#
def test_from_native_empty_override(self):
#
"""
#
Make sure you can override from_native() behavior regarding empty values.
#
"""
#
f = serializers.ChoiceField(choices=SAMPLE_CHOICES, empty=None)
#
self.assertEqual(f.from_native(''), None)
#
self.assertEqual(f.from_native(None), None)
#
def test_metadata_choices(self):
#
"""
#
Make sure proper choices are included in the field's metadata.
#
"""
#
choices = [{'value': v, 'display_name': n} for v, n in SAMPLE_CHOICES]
#
f = serializers.ChoiceField(choices=SAMPLE_CHOICES)
#
self.assertEqual(f.metadata()['choices'], choices)
#
def test_metadata_choices_not_required(self):
#
"""
#
Make sure proper choices are included in the field's metadata.
#
"""
#
choices = [{'value': v, 'display_name': n}
#
for v, n in models.fields.BLANK_CHOICE_DASH + SAMPLE_CHOICES]
#
f = serializers.ChoiceField(required=False, choices=SAMPLE_CHOICES)
#
self.assertEqual(f.metadata()['choices'], choices)
#
class EmailFieldTests(TestCase):
#
"""
#
Tests for EmailField attribute values
#
"""
#
class EmailFieldModel(RESTFrameworkModel):
#
email_field = models.EmailField(blank=True)
#
class EmailFieldWithGivenMaxLengthModel(RESTFrameworkModel):
#
email_field = models.EmailField(max_length=150, blank=True)
#
def test_default_model_value(self):
#
class EmailFieldSerializer(serializers.ModelSerializer):
#
class Meta:
#
model = self.EmailFieldModel
#
serializer = EmailFieldSerializer(data={})
#
self.assertEqual(serializer.is_valid(), True)
#
self.assertEqual(getattr(serializer.fields['email_field'], 'max_length'), 75)
#
def test_given_model_value(self):
#
class EmailFieldSerializer(serializers.ModelSerializer):
#
class Meta:
#
model = self.EmailFieldWithGivenMaxLengthModel
#
serializer = EmailFieldSerializer(data={})
#
self.assertEqual(serializer.is_valid(), True)
#
self.assertEqual(getattr(serializer.fields['email_field'], 'max_length'), 150)
#
def test_given_serializer_value(self):
#
class EmailFieldSerializer(serializers.ModelSerializer):
#
email_field = serializers.EmailField(source='email_field', max_length=20, required=False)
#
class Meta:
#
model = self.EmailFieldModel
#
serializer = EmailFieldSerializer(data={})
#
self.assertEqual(serializer.is_valid(), True)
#
self.assertEqual(getattr(serializer.fields['email_field'], 'max_length'), 20)
#
class SlugFieldTests(TestCase):
#
"""
#
Tests for SlugField attribute values
#
"""
#
class SlugFieldModel(RESTFrameworkModel):
#
slug_field = models.SlugField(blank=True)
#
class SlugFieldWithGivenMaxLengthModel(RESTFrameworkModel):
#
slug_field = models.SlugField(max_length=84, blank=True)
#
def test_default_model_value(self):
#
class SlugFieldSerializer(serializers.ModelSerializer):
#
class Meta:
#
model = self.SlugFieldModel
#
serializer = SlugFieldSerializer(data={})
#
self.assertEqual(serializer.is_valid(), True)
#
self.assertEqual(getattr(serializer.fields['slug_field'], 'max_length'), 50)
#
def test_given_model_value(self):
#
class SlugFieldSerializer(serializers.ModelSerializer):
#
class Meta:
#
model = self.SlugFieldWithGivenMaxLengthModel
#
serializer = SlugFieldSerializer(data={})
#
self.assertEqual(serializer.is_valid(), True)
#
self.assertEqual(getattr(serializer.fields['slug_field'], 'max_length'), 84)
#
def test_given_serializer_value(self):
#
class SlugFieldSerializer(serializers.ModelSerializer):
#
slug_field = serializers.SlugField(source='slug_field',
#
max_length=20, required=False)
#
class Meta:
#
model = self.SlugFieldModel
#
serializer = SlugFieldSerializer(data={})
#
self.assertEqual(serializer.is_valid(), True)
#
self.assertEqual(getattr(serializer.fields['slug_field'],
#
'max_length'), 20)
#
def test_invalid_slug(self):
#
"""
#
Make sure an invalid slug raises ValidationError
#
"""
#
class SlugFieldSerializer(serializers.ModelSerializer):
#
slug_field = serializers.SlugField(source='slug_field', max_length=20, required=True)
class
Meta
:
model
=
self
.
SlugFieldModel
#
class Meta:
#
model = self.SlugFieldModel
s
=
SlugFieldSerializer
(
data
=
{
'slug_field'
:
'a b'
})
#
s = SlugFieldSerializer(data={'slug_field': 'a b'})
self
.
assertEqual
(
s
.
is_valid
(),
False
)
self
.
assertEqual
(
s
.
errors
,
{
'slug_field'
:
[
"Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens."
]})
#
self.assertEqual(s.is_valid(), False)
#
self.assertEqual(s.errors, {'slug_field': ["Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens."]})
class
URLFieldTests
(
TestCase
):
"""
Tests for URLField attribute values.
#
class URLFieldTests(TestCase):
#
"""
#
Tests for URLField attribute values.
(Includes test for #1210, checking that validators can be overridden.)
"""
#
(Includes test for #1210, checking that validators can be overridden.)
#
"""
class
URLFieldModel
(
RESTFrameworkModel
):
url_field
=
models
.
URLField
(
blank
=
True
)
#
class URLFieldModel(RESTFrameworkModel):
#
url_field = models.URLField(blank=True)
class
URLFieldWithGivenMaxLengthModel
(
RESTFrameworkModel
):
url_field
=
models
.
URLField
(
max_length
=
128
,
blank
=
True
)
#
class URLFieldWithGivenMaxLengthModel(RESTFrameworkModel):
#
url_field = models.URLField(max_length=128, blank=True)
def
test_default_model_value
(
self
):
class
URLFieldSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
self
.
URLFieldModel
#
def test_default_model_value(self):
#
class URLFieldSerializer(serializers.ModelSerializer):
#
class Meta:
#
model = self.URLFieldModel
serializer
=
URLFieldSerializer
(
data
=
{})
self
.
assertEqual
(
serializer
.
is_valid
(),
True
)
self
.
assertEqual
(
getattr
(
serializer
.
fields
[
'url_field'
],
'max_length'
),
200
)
#
serializer = URLFieldSerializer(data={})
#
self.assertEqual(serializer.is_valid(), True)
#
self.assertEqual(getattr(serializer.fields['url_field'],
#
'max_length'), 200)
def
test_given_model_value
(
self
):
class
URLFieldSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
self
.
URLFieldWithGivenMaxLengthModel
#
def test_given_model_value(self):
#
class URLFieldSerializer(serializers.ModelSerializer):
#
class Meta:
#
model = self.URLFieldWithGivenMaxLengthModel
serializer
=
URLFieldSerializer
(
data
=
{})
self
.
assertEqual
(
serializer
.
is_valid
(),
True
)
self
.
assertEqual
(
getattr
(
serializer
.
fields
[
'url_field'
],
'max_length'
),
128
)
#
serializer = URLFieldSerializer(data={})
#
self.assertEqual(serializer.is_valid(), True)
#
self.assertEqual(getattr(serializer.fields['url_field'],
#
'max_length'), 128)
def
test_given_serializer_value
(
self
):
class
URLFieldSerializer
(
serializers
.
ModelSerializer
):
url_field
=
serializers
.
URLField
(
source
=
'url_field'
,
max_length
=
20
,
required
=
False
)
#
def test_given_serializer_value(self):
#
class URLFieldSerializer(serializers.ModelSerializer):
#
url_field = serializers.URLField(source='url_field',
#
max_length=20, required=False)
class
Meta
:
model
=
self
.
URLFieldWithGivenMaxLengthModel
#
class Meta:
#
model = self.URLFieldWithGivenMaxLengthModel
serializer
=
URLFieldSerializer
(
data
=
{})
self
.
assertEqual
(
serializer
.
is_valid
(),
True
)
self
.
assertEqual
(
getattr
(
serializer
.
fields
[
'url_field'
],
'max_length'
),
20
)
#
serializer = URLFieldSerializer(data={})
#
self.assertEqual(serializer.is_valid(), True)
#
self.assertEqual(getattr(serializer.fields['url_field'],
#
'max_length'), 20)
def
test_validators_can_be_overridden
(
self
):
url_field
=
serializers
.
URLField
(
validators
=
[])
validators
=
url_field
.
validators
self
.
assertEqual
([],
validators
,
'Passing `validators` kwarg should have overridden default validators'
)
#
def test_validators_can_be_overridden(self):
#
url_field = serializers.URLField(validators=[])
#
validators = url_field.validators
#
self.assertEqual([], validators, 'Passing `validators` kwarg should have overridden default validators')
class
FieldMetadata
(
TestCase
):
def
setUp
(
self
):
self
.
required_field
=
serializers
.
Field
()
self
.
required_field
.
label
=
uuid4
()
.
hex
self
.
required_field
.
required
=
True
#
class FieldMetadata(TestCase):
#
def setUp(self):
#
self.required_field = serializers.Field()
#
self.required_field.label = uuid4().hex
#
self.required_field.required = True
self
.
optional_field
=
serializers
.
Field
()
self
.
optional_field
.
label
=
uuid4
()
.
hex
self
.
optional_field
.
required
=
False
#
self.optional_field = serializers.Field()
#
self.optional_field.label = uuid4().hex
#
self.optional_field.required = False
def
test_required
(
self
):
self
.
assertEqual
(
self
.
required_field
.
metadata
()[
'required'
],
True
)
#
def test_required(self):
#
self.assertEqual(self.required_field.metadata()['required'], True)
def
test_optional
(
self
):
self
.
assertEqual
(
self
.
optional_field
.
metadata
()[
'required'
],
False
)
#
def test_optional(self):
#
self.assertEqual(self.optional_field.metadata()['required'], False)
def
test_label
(
self
):
for
field
in
(
self
.
required_field
,
self
.
optional_field
):
self
.
assertEqual
(
field
.
metadata
()[
'label'
],
field
.
label
)
#
def test_label(self):
#
for field in (self.required_field, self.optional_field):
#
self.assertEqual(field.metadata()['label'], field.label)
class
FieldCallableDefault
(
TestCase
):
def
setUp
(
self
):
self
.
simple_callable
=
lambda
:
'foo bar'
#
class FieldCallableDefault(TestCase):
#
def setUp(self):
#
self.simple_callable = lambda: 'foo bar'
def
test_default_can_be_simple_callable
(
self
):
"""
Ensure that the 'default' argument can also be a simple callable.
"""
field
=
serializers
.
WritableField
(
default
=
self
.
simple_callable
)
into
=
{}
field
.
field_from_native
({},
{},
'field'
,
into
)
self
.
assertEqual
(
into
,
{
'field'
:
'foo bar'
})
#
def test_default_can_be_simple_callable(self):
#
"""
#
Ensure that the 'default' argument can also be a simple callable.
#
"""
#
field = serializers.WritableField(default=self.simple_callable)
#
into = {}
#
field.field_from_native({}, {}, 'field', into)
#
self.assertEqual(into, {'field': 'foo bar'})
class
CustomIntegerField
(
TestCase
):
"""
Test that custom fields apply min_value and max_value constraints
"""
def
test_custom_fields_can_be_validated_for_value
(
self
):
#
class CustomIntegerField(TestCase):
#
"""
#
Test that custom fields apply min_value and max_value constraints
#
"""
#
def test_custom_fields_can_be_validated_for_value(self):
class
MoneyField
(
models
.
PositiveIntegerField
):
pass
#
class MoneyField(models.PositiveIntegerField):
#
pass
class
EntryModel
(
models
.
Model
):
bank
=
MoneyField
(
validators
=
[
validators
.
MaxValueValidator
(
100
)])
#
class EntryModel(models.Model):
#
bank = MoneyField(validators=[validators.MaxValueValidator(100)])
class
EntrySerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
EntryModel
#
class EntrySerializer(serializers.ModelSerializer):
#
class Meta:
#
model = EntryModel
entry
=
EntryModel
(
bank
=
1
)
#
entry = EntryModel(bank=1)
serializer
=
EntrySerializer
(
entry
,
data
=
{
"bank"
:
11
})
self
.
assertTrue
(
serializer
.
is_valid
())
#
serializer = EntrySerializer(entry, data={"bank": 11})
#
self.assertTrue(serializer.is_valid())
serializer
=
EntrySerializer
(
entry
,
data
=
{
"bank"
:
-
1
})
self
.
assertFalse
(
serializer
.
is_valid
())
#
serializer = EntrySerializer(entry, data={"bank": -1})
#
self.assertFalse(serializer.is_valid())
serializer
=
EntrySerializer
(
entry
,
data
=
{
"bank"
:
101
})
self
.
assertFalse
(
serializer
.
is_valid
())
#
serializer = EntrySerializer(entry, data={"bank": 101})
#
self.assertFalse(serializer.is_valid())
class
BooleanField
(
TestCase
):
"""
Tests for BooleanField
"""
def
test_boolean_required
(
self
):
class
BooleanRequiredSerializer
(
serializers
.
Serializer
):
bool_field
=
serializers
.
BooleanField
(
required
=
True
)
#
class BooleanField(TestCase):
#
"""
#
Tests for BooleanField
#
"""
#
def test_boolean_required(self):
#
class BooleanRequiredSerializer(serializers.Serializer):
#
bool_field = serializers.BooleanField(required=True)
self
.
assertFalse
(
BooleanRequiredSerializer
(
data
=
{})
.
is_valid
())
#
self.assertFalse(BooleanRequiredSerializer(data={}).is_valid())
class
SerializerMethodFieldTest
(
TestCase
):
"""
Tests for the SerializerMethodField field_to_native() behavior
"""
class
SerializerTest
(
serializers
.
Serializer
):
def
get_my_test
(
self
,
obj
):
return
obj
.
my_test
[
0
:
5
]
#
class SerializerMethodFieldTest(TestCase):
#
"""
#
Tests for the SerializerMethodField field_to_native() behavior
#
"""
#
class SerializerTest(serializers.Serializer):
#
def get_my_test(self, obj):
#
return obj.my_test[0:5]
class
Example
():
my_test
=
'Hey, this is a test !'
#
class Example():
#
my_test = 'Hey, this is a test !'
def
test_field_to_native
(
self
):
s
=
serializers
.
SerializerMethodField
(
'get_my_test'
)
s
.
initialize
(
self
.
SerializerTest
(),
'name'
)
result
=
s
.
field_to_native
(
self
.
Example
(),
None
)
self
.
assertEqual
(
result
,
'Hey, '
)
#
def test_field_to_native(self):
#
s = serializers.SerializerMethodField('get_my_test')
#
s.initialize(self.SerializerTest(), 'name')
#
result = s.field_to_native(self.Example(), None)
#
self.assertEqual(result, 'Hey, ')
tests/test_files.py
View file @
f2852811
from
__future__
import
unicode_literals
from
django.test
import
TestCase
from
django.utils
import
six
from
rest_framework
import
serializers
from
rest_framework.compat
import
BytesIO
import
datetime
class
UploadedFile
(
object
):
def
__init__
(
self
,
file
=
None
,
created
=
None
):
self
.
file
=
file
self
.
created
=
created
or
datetime
.
datetime
.
now
()
class
UploadedFileSerializer
(
serializers
.
Serializer
):
file
=
serializers
.
FileField
(
required
=
False
)
created
=
serializers
.
DateTimeField
()
def
restore_object
(
self
,
attrs
,
instance
=
None
):
if
instance
:
instance
.
file
=
attrs
[
'file'
]
instance
.
created
=
attrs
[
'created'
]
return
instance
return
UploadedFile
(
**
attrs
)
class
FileSerializerTests
(
TestCase
):
def
test_create
(
self
):
now
=
datetime
.
datetime
.
now
()
file
=
BytesIO
(
six
.
b
(
'stuff'
))
file
.
name
=
'stuff.txt'
file
.
size
=
len
(
file
.
getvalue
())
serializer
=
UploadedFileSerializer
(
data
=
{
'created'
:
now
},
files
=
{
'file'
:
file
})
uploaded_file
=
UploadedFile
(
file
=
file
,
created
=
now
)
self
.
assertTrue
(
serializer
.
is_valid
())
self
.
assertEqual
(
serializer
.
object
.
created
,
uploaded_file
.
created
)
self
.
assertEqual
(
serializer
.
object
.
file
,
uploaded_file
.
file
)
self
.
assertFalse
(
serializer
.
object
is
uploaded_file
)
def
test_creation_failure
(
self
):
"""
Passing files=None should result in an ValidationError
Regression test for:
https://github.com/tomchristie/django-rest-framework/issues/542
"""
now
=
datetime
.
datetime
.
now
()
serializer
=
UploadedFileSerializer
(
data
=
{
'created'
:
now
})
self
.
assertTrue
(
serializer
.
is_valid
())
self
.
assertEqual
(
serializer
.
object
.
created
,
now
)
self
.
assertIsNone
(
serializer
.
object
.
file
)
def
test_remove_with_empty_string
(
self
):
"""
Passing empty string as data should cause file to be removed
Test for:
https://github.com/tomchristie/django-rest-framework/issues/937
"""
now
=
datetime
.
datetime
.
now
()
file
=
BytesIO
(
six
.
b
(
'stuff'
))
file
.
name
=
'stuff.txt'
file
.
size
=
len
(
file
.
getvalue
())
uploaded_file
=
UploadedFile
(
file
=
file
,
created
=
now
)
serializer
=
UploadedFileSerializer
(
instance
=
uploaded_file
,
data
=
{
'created'
:
now
,
'file'
:
''
})
self
.
assertTrue
(
serializer
.
is_valid
())
self
.
assertEqual
(
serializer
.
object
.
created
,
uploaded_file
.
created
)
self
.
assertIsNone
(
serializer
.
object
.
file
)
def
test_validation_error_with_non_file
(
self
):
"""
Passing non-files should raise a validation error.
"""
now
=
datetime
.
datetime
.
now
()
errmsg
=
'No file was submitted. Check the encoding type on the form.'
serializer
=
UploadedFileSerializer
(
data
=
{
'created'
:
now
,
'file'
:
'abc'
})
self
.
assertFalse
(
serializer
.
is_valid
())
self
.
assertEqual
(
serializer
.
errors
,
{
'file'
:
[
errmsg
]})
def
test_validation_with_no_data
(
self
):
"""
Validation should still function when no data dictionary is provided.
"""
uploaded_file
=
BytesIO
(
six
.
b
(
'stuff'
))
uploaded_file
.
name
=
'stuff.txt'
uploaded_file
.
size
=
len
(
uploaded_file
.
getvalue
())
serializer
=
UploadedFileSerializer
(
files
=
{
'file'
:
uploaded_file
})
self
.
assertFalse
(
serializer
.
is_valid
())
#
from __future__ import unicode_literals
#
from django.test import TestCase
#
from django.utils import six
#
from rest_framework import serializers
#
from rest_framework.compat import BytesIO
#
import datetime
#
class UploadedFile(object):
#
def __init__(self, file=None, created=None):
#
self.file = file
#
self.created = created or datetime.datetime.now()
#
class UploadedFileSerializer(serializers.Serializer):
#
file = serializers.FileField(required=False)
#
created = serializers.DateTimeField()
#
def restore_object(self, attrs, instance=None):
#
if instance:
#
instance.file = attrs['file']
#
instance.created = attrs['created']
#
return instance
#
return UploadedFile(**attrs)
#
class FileSerializerTests(TestCase):
#
def test_create(self):
#
now = datetime.datetime.now()
#
file = BytesIO(six.b('stuff'))
#
file.name = 'stuff.txt'
#
file.size = len(file.getvalue())
#
serializer = UploadedFileSerializer(data={'created': now}, files={'file': file})
#
uploaded_file = UploadedFile(file=file, created=now)
#
self.assertTrue(serializer.is_valid())
#
self.assertEqual(serializer.object.created, uploaded_file.created)
#
self.assertEqual(serializer.object.file, uploaded_file.file)
#
self.assertFalse(serializer.object is uploaded_file)
#
def test_creation_failure(self):
#
"""
#
Passing files=None should result in an ValidationError
#
Regression test for:
#
https://github.com/tomchristie/django-rest-framework/issues/542
#
"""
#
now = datetime.datetime.now()
#
serializer = UploadedFileSerializer(data={'created': now})
#
self.assertTrue(serializer.is_valid())
#
self.assertEqual(serializer.object.created, now)
#
self.assertIsNone(serializer.object.file)
#
def test_remove_with_empty_string(self):
#
"""
#
Passing empty string as data should cause file to be removed
#
Test for:
#
https://github.com/tomchristie/django-rest-framework/issues/937
#
"""
#
now = datetime.datetime.now()
#
file = BytesIO(six.b('stuff'))
#
file.name = 'stuff.txt'
#
file.size = len(file.getvalue())
#
uploaded_file = UploadedFile(file=file, created=now)
#
serializer = UploadedFileSerializer(instance=uploaded_file, data={'created': now, 'file': ''})
#
self.assertTrue(serializer.is_valid())
#
self.assertEqual(serializer.object.created, uploaded_file.created)
#
self.assertIsNone(serializer.object.file)
#
def test_validation_error_with_non_file(self):
#
"""
#
Passing non-files should raise a validation error.
#
"""
#
now = datetime.datetime.now()
#
errmsg = 'No file was submitted. Check the encoding type on the form.'
#
serializer = UploadedFileSerializer(data={'created': now, 'file': 'abc'})
#
self.assertFalse(serializer.is_valid())
#
self.assertEqual(serializer.errors, {'file': [errmsg]})
#
def test_validation_with_no_data(self):
#
"""
#
Validation should still function when no data dictionary is provided.
#
"""
#
uploaded_file = BytesIO(six.b('stuff'))
#
uploaded_file.name = 'stuff.txt'
#
uploaded_file.size = len(uploaded_file.getvalue())
#
serializer = UploadedFileSerializer(files={'file': uploaded_file})
#
self.assertFalse(serializer.is_valid())
tests/test_genericrelations.py
View file @
f2852811
from
__future__
import
unicode_literals
from
django.contrib.contenttypes.models
import
ContentType
from
django.contrib.contenttypes.generic
import
GenericRelation
,
GenericForeignKey
from
django.db
import
models
from
django.test
import
TestCase
from
rest_framework
import
serializers
from
rest_framework.compat
import
python_2_unicode_compatible
@python_2_unicode_compatible
class
Tag
(
models
.
Model
):
"""
Tags have a descriptive slug, and are attached to an arbitrary object.
"""
tag
=
models
.
SlugField
()
content_type
=
models
.
ForeignKey
(
ContentType
)
object_id
=
models
.
PositiveIntegerField
()
tagged_item
=
GenericForeignKey
(
'content_type'
,
'object_id'
)
def
__str__
(
self
):
return
self
.
tag
@python_2_unicode_compatible
class
Bookmark
(
models
.
Model
):
"""
A URL bookmark that may have multiple tags attached.
"""
url
=
models
.
URLField
()
tags
=
GenericRelation
(
Tag
)
def
__str__
(
self
):
return
'Bookmark:
%
s'
%
self
.
url
@python_2_unicode_compatible
class
Note
(
models
.
Model
):
"""
A textual note that may have multiple tags attached.
"""
text
=
models
.
TextField
()
tags
=
GenericRelation
(
Tag
)
def
__str__
(
self
):
return
'Note:
%
s'
%
self
.
text
class
TestGenericRelations
(
TestCase
):
def
setUp
(
self
):
self
.
bookmark
=
Bookmark
.
objects
.
create
(
url
=
'https://www.djangoproject.com/'
)
Tag
.
objects
.
create
(
tagged_item
=
self
.
bookmark
,
tag
=
'django'
)
Tag
.
objects
.
create
(
tagged_item
=
self
.
bookmark
,
tag
=
'python'
)
self
.
note
=
Note
.
objects
.
create
(
text
=
'Remember the milk'
)
Tag
.
objects
.
create
(
tagged_item
=
self
.
note
,
tag
=
'reminder'
)
def
test_generic_relation
(
self
):
"""
Test a relationship that spans a GenericRelation field.
IE. A reverse generic relationship.
"""
class
BookmarkSerializer
(
serializers
.
ModelSerializer
):
tags
=
serializers
.
RelatedField
(
many
=
True
)
class
Meta
:
model
=
Bookmark
exclude
=
(
'id'
,)
serializer
=
BookmarkSerializer
(
self
.
bookmark
)
expected
=
{
'tags'
:
[
'django'
,
'python'
],
'url'
:
'https://www.djangoproject.com/'
}
self
.
assertEqual
(
serializer
.
data
,
expected
)
def
test_generic_nested_relation
(
self
):
"""
Test saving a GenericRelation field via a nested serializer.
"""
class
TagSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
Tag
exclude
=
(
'content_type'
,
'object_id'
)
class
BookmarkSerializer
(
serializers
.
ModelSerializer
):
tags
=
TagSerializer
(
many
=
True
)
class
Meta
:
model
=
Bookmark
exclude
=
(
'id'
,)
data
=
{
'url'
:
'https://docs.djangoproject.com/'
,
'tags'
:
[
{
'tag'
:
'contenttypes'
},
{
'tag'
:
'genericrelations'
},
]
}
serializer
=
BookmarkSerializer
(
data
=
data
)
self
.
assertTrue
(
serializer
.
is_valid
())
serializer
.
save
()
self
.
assertEqual
(
serializer
.
object
.
tags
.
count
(),
2
)
def
test_generic_fk
(
self
):
"""
Test a relationship that spans a GenericForeignKey field.
IE. A forward generic relationship.
"""
class
TagSerializer
(
serializers
.
ModelSerializer
):
tagged_item
=
serializers
.
RelatedField
()
class
Meta
:
model
=
Tag
exclude
=
(
'id'
,
'content_type'
,
'object_id'
)
serializer
=
TagSerializer
(
Tag
.
objects
.
all
(),
many
=
True
)
expected
=
[
{
'tag'
:
'django'
,
'tagged_item'
:
'Bookmark: https://www.djangoproject.com/'
},
{
'tag'
:
'python'
,
'tagged_item'
:
'Bookmark: https://www.djangoproject.com/'
},
{
'tag'
:
'reminder'
,
'tagged_item'
:
'Note: Remember the milk'
}
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
def
test_restore_object_generic_fk
(
self
):
"""
Ensure an object with a generic foreign key can be restored.
"""
class
TagSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
Tag
exclude
=
(
'content_type'
,
'object_id'
)
serializer
=
TagSerializer
()
bookmark
=
Bookmark
(
url
=
'http://example.com'
)
attrs
=
{
'tagged_item'
:
bookmark
,
'tag'
:
'example'
}
tag
=
serializer
.
restore_object
(
attrs
)
self
.
assertEqual
(
tag
.
tagged_item
,
bookmark
)
#
from __future__ import unicode_literals
#
from django.contrib.contenttypes.models import ContentType
#
from django.contrib.contenttypes.generic import GenericRelation, GenericForeignKey
#
from django.db import models
#
from django.test import TestCase
#
from rest_framework import serializers
#
from rest_framework.compat import python_2_unicode_compatible
#
@python_2_unicode_compatible
#
class Tag(models.Model):
#
"""
#
Tags have a descriptive slug, and are attached to an arbitrary object.
#
"""
#
tag = models.SlugField()
#
content_type = models.ForeignKey(ContentType)
#
object_id = models.PositiveIntegerField()
#
tagged_item = GenericForeignKey('content_type', 'object_id')
#
def __str__(self):
#
return self.tag
#
@python_2_unicode_compatible
#
class Bookmark(models.Model):
#
"""
#
A URL bookmark that may have multiple tags attached.
#
"""
#
url = models.URLField()
#
tags = GenericRelation(Tag)
#
def __str__(self):
#
return 'Bookmark: %s' % self.url
#
@python_2_unicode_compatible
#
class Note(models.Model):
#
"""
#
A textual note that may have multiple tags attached.
#
"""
#
text = models.TextField()
#
tags = GenericRelation(Tag)
#
def __str__(self):
#
return 'Note: %s' % self.text
#
class TestGenericRelations(TestCase):
#
def setUp(self):
#
self.bookmark = Bookmark.objects.create(url='https://www.djangoproject.com/')
#
Tag.objects.create(tagged_item=self.bookmark, tag='django')
#
Tag.objects.create(tagged_item=self.bookmark, tag='python')
#
self.note = Note.objects.create(text='Remember the milk')
#
Tag.objects.create(tagged_item=self.note, tag='reminder')
#
def test_generic_relation(self):
#
"""
#
Test a relationship that spans a GenericRelation field.
#
IE. A reverse generic relationship.
#
"""
#
class BookmarkSerializer(serializers.ModelSerializer):
#
tags = serializers.RelatedField(many=True)
#
class Meta:
#
model = Bookmark
#
exclude = ('id',)
#
serializer = BookmarkSerializer(self.bookmark)
#
expected = {
#
'tags': ['django', 'python'],
#
'url': 'https://www.djangoproject.com/'
#
}
#
self.assertEqual(serializer.data, expected)
#
def test_generic_nested_relation(self):
#
"""
#
Test saving a GenericRelation field via a nested serializer.
#
"""
#
class TagSerializer(serializers.ModelSerializer):
#
class Meta:
#
model = Tag
#
exclude = ('content_type', 'object_id')
#
class BookmarkSerializer(serializers.ModelSerializer):
#
tags = TagSerializer(many=True)
#
class Meta:
#
model = Bookmark
#
exclude = ('id',)
#
data = {
#
'url': 'https://docs.djangoproject.com/',
#
'tags': [
#
{'tag': 'contenttypes'},
#
{'tag': 'genericrelations'},
#
]
#
}
#
serializer = BookmarkSerializer(data=data)
#
self.assertTrue(serializer.is_valid())
#
serializer.save()
#
self.assertEqual(serializer.object.tags.count(), 2)
#
def test_generic_fk(self):
#
"""
#
Test a relationship that spans a GenericForeignKey field.
#
IE. A forward generic relationship.
#
"""
#
class TagSerializer(serializers.ModelSerializer):
#
tagged_item = serializers.RelatedField()
#
class Meta:
#
model = Tag
#
exclude = ('id', 'content_type', 'object_id')
#
serializer = TagSerializer(Tag.objects.all(), many=True)
#
expected = [
#
{
#
'tag': 'django',
#
'tagged_item': 'Bookmark: https://www.djangoproject.com/'
#
},
#
{
#
'tag': 'python',
#
'tagged_item': 'Bookmark: https://www.djangoproject.com/'
#
},
#
{
#
'tag': 'reminder',
#
'tagged_item': 'Note: Remember the milk'
#
}
#
]
#
self.assertEqual(serializer.data, expected)
#
def test_restore_object_generic_fk(self):
#
"""
#
Ensure an object with a generic foreign key can be restored.
#
"""
#
class TagSerializer(serializers.ModelSerializer):
#
class Meta:
#
model = Tag
#
exclude = ('content_type', 'object_id')
#
serializer = TagSerializer()
#
bookmark = Bookmark(url='http://example.com')
#
attrs = {'tagged_item': bookmark, 'tag': 'example'}
#
tag = serializer.restore_object(attrs)
#
self.assertEqual(tag.tagged_item, bookmark)
tests/test_generics.py
View file @
f2852811
...
...
@@ -33,13 +33,9 @@ class InstanceView(generics.RetrieveUpdateDestroyAPIView):
"""
Example description for OPTIONS.
"""
queryset
=
BasicModel
.
objects
.
all
(
)
queryset
=
BasicModel
.
objects
.
exclude
(
text
=
'filtered out'
)
serializer_class
=
BasicSerializer
def
get_queryset
(
self
):
queryset
=
super
(
InstanceView
,
self
)
.
get_queryset
()
return
queryset
.
exclude
(
text
=
'filtered out'
)
class
FKInstanceView
(
generics
.
RetrieveUpdateDestroyAPIView
):
"""
...
...
@@ -50,11 +46,11 @@ class FKInstanceView(generics.RetrieveUpdateDestroyAPIView):
class
SlugSerializer
(
serializers
.
ModelSerializer
):
slug
=
serializers
.
Field
(
)
# read only
slug
=
serializers
.
Field
(
read_only
=
True
)
class
Meta
:
model
=
SlugBasedModel
exclude
=
(
'id'
,
)
fields
=
(
'text'
,
'slug'
)
class
SlugBasedInstanceView
(
InstanceView
):
...
...
@@ -125,46 +121,46 @@ class TestRootView(TestCase):
self
.
assertEqual
(
response
.
status_code
,
status
.
HTTP_405_METHOD_NOT_ALLOWED
)
self
.
assertEqual
(
response
.
data
,
{
"detail"
:
"Method 'DELETE' not allowed."
})
def
test_options_root_view
(
self
):
"""
OPTIONS requests to ListCreateAPIView should return metadata
"""
request
=
factory
.
options
(
'/'
)
with
self
.
assertNumQueries
(
0
):
response
=
self
.
view
(
request
)
.
render
()
expected
=
{
'parses'
:
[
'application/json'
,
'application/x-www-form-urlencoded'
,
'multipart/form-data'
],
'renders'
:
[
'application/json'
,
'text/html'
],
'name'
:
'Root'
,
'description'
:
'Example description for OPTIONS.'
,
'actions'
:
{
'POST'
:
{
'text'
:
{
'max_length'
:
100
,
'read_only'
:
False
,
'required'
:
True
,
'type'
:
'string'
,
"label"
:
"Text comes here"
,
"help_text"
:
"Text description."
},
'id'
:
{
'read_only'
:
True
,
'required'
:
False
,
'type'
:
'integer'
,
'label'
:
'ID'
,
},
}
}
}
self
.
assertEqual
(
response
.
status_code
,
status
.
HTTP_200_OK
)
self
.
assertEqual
(
response
.
data
,
expected
)
#
def test_options_root_view(self):
#
"""
#
OPTIONS requests to ListCreateAPIView should return metadata
#
"""
#
request = factory.options('/')
#
with self.assertNumQueries(0):
#
response = self.view(request).render()
#
expected = {
#
'parses': [
#
'application/json',
#
'application/x-www-form-urlencoded',
#
'multipart/form-data'
#
],
#
'renders': [
#
'application/json',
#
'text/html'
#
],
#
'name': 'Root',
#
'description': 'Example description for OPTIONS.',
#
'actions': {
#
'POST': {
#
'text': {
#
'max_length': 100,
#
'read_only': False,
#
'required': True,
#
'type': 'string',
#
"label": "Text comes here",
#
"help_text": "Text description."
#
},
#
'id': {
#
'read_only': True,
#
'required': False,
#
'type': 'integer',
#
'label': 'ID',
#
},
#
}
#
}
#
}
#
self.assertEqual(response.status_code, status.HTTP_200_OK)
#
self.assertEqual(response.data, expected)
def
test_post_cannot_set_id
(
self
):
"""
...
...
@@ -223,10 +219,10 @@ class TestInstanceView(TestCase):
"""
data
=
{
'text'
:
'foobar'
}
request
=
factory
.
put
(
'/1'
,
data
,
format
=
'json'
)
with
self
.
assertNumQueries
(
2
):
with
self
.
assertNumQueries
(
3
):
response
=
self
.
view
(
request
,
pk
=
'1'
)
.
render
()
self
.
assertEqual
(
response
.
status_code
,
status
.
HTTP_200_OK
)
self
.
assertEqual
(
response
.
data
,
{
'id'
:
1
,
'text'
:
'foobar'
})
self
.
assertEqual
(
dict
(
response
.
data
)
,
{
'id'
:
1
,
'text'
:
'foobar'
})
updated
=
self
.
objects
.
get
(
id
=
1
)
self
.
assertEqual
(
updated
.
text
,
'foobar'
)
...
...
@@ -237,7 +233,7 @@ class TestInstanceView(TestCase):
data
=
{
'text'
:
'foobar'
}
request
=
factory
.
patch
(
'/1'
,
data
,
format
=
'json'
)
with
self
.
assertNumQueries
(
2
):
with
self
.
assertNumQueries
(
3
):
response
=
self
.
view
(
request
,
pk
=
1
)
.
render
()
self
.
assertEqual
(
response
.
status_code
,
status
.
HTTP_200_OK
)
self
.
assertEqual
(
response
.
data
,
{
'id'
:
1
,
'text'
:
'foobar'
})
...
...
@@ -256,88 +252,88 @@ class TestInstanceView(TestCase):
ids
=
[
obj
.
id
for
obj
in
self
.
objects
.
all
()]
self
.
assertEqual
(
ids
,
[
2
,
3
])
def
test_options_instance_view
(
self
):
"""
OPTIONS requests to RetrieveUpdateDestroyAPIView should return metadata
"""
request
=
factory
.
options
(
'/1'
)
with
self
.
assertNumQueries
(
1
):
response
=
self
.
view
(
request
,
pk
=
1
)
.
render
()
expected
=
{
'parses'
:
[
'application/json'
,
'application/x-www-form-urlencoded'
,
'multipart/form-data'
],
'renders'
:
[
'application/json'
,
'text/html'
],
'name'
:
'Instance'
,
'description'
:
'Example description for OPTIONS.'
,
'actions'
:
{
'PUT'
:
{
'text'
:
{
'max_length'
:
100
,
'read_only'
:
False
,
'required'
:
True
,
'type'
:
'string'
,
'label'
:
'Text comes here'
,
'help_text'
:
'Text description.'
},
'id'
:
{
'read_only'
:
True
,
'required'
:
False
,
'type'
:
'integer'
,
'label'
:
'ID'
,
},
}
}
}
self
.
assertEqual
(
response
.
status_code
,
status
.
HTTP_200_OK
)
self
.
assertEqual
(
response
.
data
,
expected
)
def
test_options_before_instance_create
(
self
):
"""
OPTIONS requests to RetrieveUpdateDestroyAPIView should return metadata
before the instance has been created
"""
request
=
factory
.
options
(
'/999'
)
with
self
.
assertNumQueries
(
1
):
response
=
self
.
view
(
request
,
pk
=
999
)
.
render
()
expected
=
{
'parses'
:
[
'application/json'
,
'application/x-www-form-urlencoded'
,
'multipart/form-data'
],
'renders'
:
[
'application/json'
,
'text/html'
],
'name'
:
'Instance'
,
'description'
:
'Example description for OPTIONS.'
,
'actions'
:
{
'PUT'
:
{
'text'
:
{
'max_length'
:
100
,
'read_only'
:
False
,
'required'
:
True
,
'type'
:
'string'
,
'label'
:
'Text comes here'
,
'help_text'
:
'Text description.'
},
'id'
:
{
'read_only'
:
True
,
'required'
:
False
,
'type'
:
'integer'
,
'label'
:
'ID'
,
},
}
}
}
self
.
assertEqual
(
response
.
status_code
,
status
.
HTTP_200_OK
)
self
.
assertEqual
(
response
.
data
,
expected
)
#
def test_options_instance_view(self):
#
"""
#
OPTIONS requests to RetrieveUpdateDestroyAPIView should return metadata
#
"""
#
request = factory.options('/1')
#
with self.assertNumQueries(1):
#
response = self.view(request, pk=1).render()
#
expected = {
#
'parses': [
#
'application/json',
#
'application/x-www-form-urlencoded',
#
'multipart/form-data'
#
],
#
'renders': [
#
'application/json',
#
'text/html'
#
],
#
'name': 'Instance',
#
'description': 'Example description for OPTIONS.',
#
'actions': {
#
'PUT': {
#
'text': {
#
'max_length': 100,
#
'read_only': False,
#
'required': True,
#
'type': 'string',
#
'label': 'Text comes here',
#
'help_text': 'Text description.'
#
},
#
'id': {
#
'read_only': True,
#
'required': False,
#
'type': 'integer',
#
'label': 'ID',
#
},
#
}
#
}
#
}
#
self.assertEqual(response.status_code, status.HTTP_200_OK)
#
self.assertEqual(response.data, expected)
#
def test_options_before_instance_create(self):
#
"""
#
OPTIONS requests to RetrieveUpdateDestroyAPIView should return metadata
#
before the instance has been created
#
"""
#
request = factory.options('/999')
#
with self.assertNumQueries(1):
#
response = self.view(request, pk=999).render()
#
expected = {
#
'parses': [
#
'application/json',
#
'application/x-www-form-urlencoded',
#
'multipart/form-data'
#
],
#
'renders': [
#
'application/json',
#
'text/html'
#
],
#
'name': 'Instance',
#
'description': 'Example description for OPTIONS.',
#
'actions': {
#
'PUT': {
#
'text': {
#
'max_length': 100,
#
'read_only': False,
#
'required': True,
#
'type': 'string',
#
'label': 'Text comes here',
#
'help_text': 'Text description.'
#
},
#
'id': {
#
'read_only': True,
#
'required': False,
#
'type': 'integer',
#
'label': 'ID',
#
},
#
}
#
}
#
}
#
self.assertEqual(response.status_code, status.HTTP_200_OK)
#
self.assertEqual(response.data, expected)
def
test_get_instance_view_incorrect_arg
(
self
):
"""
...
...
@@ -355,7 +351,7 @@ class TestInstanceView(TestCase):
"""
data
=
{
'id'
:
999
,
'text'
:
'foobar'
}
request
=
factory
.
put
(
'/1'
,
data
,
format
=
'json'
)
with
self
.
assertNumQueries
(
2
):
with
self
.
assertNumQueries
(
3
):
response
=
self
.
view
(
request
,
pk
=
1
)
.
render
()
self
.
assertEqual
(
response
.
status_code
,
status
.
HTTP_200_OK
)
self
.
assertEqual
(
response
.
data
,
{
'id'
:
1
,
'text'
:
'foobar'
})
...
...
@@ -370,7 +366,7 @@ class TestInstanceView(TestCase):
self
.
objects
.
get
(
id
=
1
)
.
delete
()
data
=
{
'text'
:
'foobar'
}
request
=
factory
.
put
(
'/1'
,
data
,
format
=
'json'
)
with
self
.
assertNumQueries
(
3
):
with
self
.
assertNumQueries
(
2
):
response
=
self
.
view
(
request
,
pk
=
1
)
.
render
()
self
.
assertEqual
(
response
.
status_code
,
status
.
HTTP_201_CREATED
)
self
.
assertEqual
(
response
.
data
,
{
'id'
:
1
,
'text'
:
'foobar'
})
...
...
@@ -396,7 +392,7 @@ class TestInstanceView(TestCase):
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
(
3
):
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
)
...
...
@@ -446,52 +442,52 @@ class TestFKInstanceView(TestCase):
]
self
.
view
=
FKInstanceView
.
as_view
()
def
test_options_root_view
(
self
):
"""
OPTIONS requests to ListCreateAPIView should return metadata
"""
request
=
factory
.
options
(
'/999'
)
with
self
.
assertNumQueries
(
1
):
response
=
self
.
view
(
request
,
pk
=
999
)
.
render
()
expected
=
{
'name'
:
'Fk Instance'
,
'description'
:
'FK: example description for OPTIONS.'
,
'renders'
:
[
'application/json'
,
'text/html'
],
'parses'
:
[
'application/json'
,
'application/x-www-form-urlencoded'
,
'multipart/form-data'
],
'actions'
:
{
'PUT'
:
{
'id'
:
{
'type'
:
'integer'
,
'required'
:
False
,
'read_only'
:
True
,
'label'
:
'ID'
},
'name'
:
{
'type'
:
'string'
,
'required'
:
True
,
'read_only'
:
False
,
'label'
:
'name'
,
'max_length'
:
100
},
'target'
:
{
'type'
:
'field'
,
'required'
:
True
,
'read_only'
:
False
,
'label'
:
'Target'
,
'help_text'
:
'Target'
}
}
}
}
self
.
assertEqual
(
response
.
status_code
,
status
.
HTTP_200_OK
)
self
.
assertEqual
(
response
.
data
,
expected
)
#
def test_options_root_view(self):
#
"""
#
OPTIONS requests to ListCreateAPIView should return metadata
#
"""
#
request = factory.options('/999')
#
with self.assertNumQueries(1):
#
response = self.view(request, pk=999).render()
#
expected = {
#
'name': 'Fk Instance',
#
'description': 'FK: example description for OPTIONS.',
#
'renders': [
#
'application/json',
#
'text/html'
#
],
#
'parses': [
#
'application/json',
#
'application/x-www-form-urlencoded',
#
'multipart/form-data'
#
],
#
'actions': {
#
'PUT': {
#
'id': {
#
'type': 'integer',
#
'required': False,
#
'read_only': True,
#
'label': 'ID'
#
},
#
'name': {
#
'type': 'string',
#
'required': True,
#
'read_only': False,
#
'label': 'name',
#
'max_length': 100
#
},
#
'target': {
#
'type': 'field',
#
'required': True,
#
'read_only': False,
#
'label': 'Target',
#
'help_text': 'Target'
#
}
#
}
#
}
#
}
#
self.assertEqual(response.status_code, status.HTTP_200_OK)
#
self.assertEqual(response.data, expected)
class
TestOverriddenGetObject
(
TestCase
):
...
...
tests/test_hyperlinkedserializers.py
View file @
f2852811
from
__future__
import
unicode_literals
import
json
from
django.test
import
TestCase
from
rest_framework
import
generics
,
status
,
serializers
from
django.conf.urls
import
patterns
,
url
from
rest_framework.settings
import
api_settings
from
rest_framework.test
import
APIRequestFactory
from
tests.models
import
(
Anchor
,
BasicModel
,
ManyToManyModel
,
BlogPost
,
BlogPostComment
,
Album
,
Photo
,
OptionalRelationModel
)
#
from __future__ import unicode_literals
#
import json
#
from django.test import TestCase
#
from rest_framework import generics, status, serializers
#
from django.conf.urls import patterns, url
#
from rest_framework.settings import api_settings
#
from rest_framework.test import APIRequestFactory
#
from tests.models import (
#
Anchor, BasicModel, ManyToManyModel, BlogPost, BlogPostComment,
#
Album, Photo, OptionalRelationModel
#
)
factory
=
APIRequestFactory
()
#
factory = APIRequestFactory()
class
BlogPostCommentSerializer
(
serializers
.
ModelSerializer
):
url
=
serializers
.
HyperlinkedIdentityField
(
view_name
=
'blogpostcomment-detail'
)
text
=
serializers
.
CharField
()
blog_post_url
=
serializers
.
HyperlinkedRelatedField
(
source
=
'blog_post'
,
view_name
=
'blogpost-detail'
)
#
class BlogPostCommentSerializer(serializers.ModelSerializer):
#
url = serializers.HyperlinkedIdentityField(view_name='blogpostcomment-detail')
#
text = serializers.CharField()
#
blog_post_url = serializers.HyperlinkedRelatedField(source='blog_post', view_name='blogpost-detail')
class
Meta
:
model
=
BlogPostComment
fields
=
(
'text'
,
'blog_post_url'
,
'url'
)
#
class Meta:
#
model = BlogPostComment
#
fields = ('text', 'blog_post_url', 'url')
class
PhotoSerializer
(
serializers
.
Serializer
):
description
=
serializers
.
CharField
()
album_url
=
serializers
.
HyperlinkedRelatedField
(
source
=
'album'
,
view_name
=
'album-detail'
,
queryset
=
Album
.
objects
.
all
(),
lookup_field
=
'title'
)
#
class PhotoSerializer(serializers.Serializer):
#
description = serializers.CharField()
#
album_url = serializers.HyperlinkedRelatedField(source='album', view_name='album-detail', queryset=Album.objects.all(), lookup_field='title')
def
restore_object
(
self
,
attrs
,
instance
=
None
):
return
Photo
(
**
attrs
)
#
def restore_object(self, attrs, instance=None):
#
return Photo(**attrs)
class
AlbumSerializer
(
serializers
.
ModelSerializer
):
url
=
serializers
.
HyperlinkedIdentityField
(
view_name
=
'album-detail'
,
lookup_field
=
'title'
)
#
class AlbumSerializer(serializers.ModelSerializer):
#
url = serializers.HyperlinkedIdentityField(view_name='album-detail', lookup_field='title')
class
Meta
:
model
=
Album
fields
=
(
'title'
,
'url'
)
#
class Meta:
#
model = Album
#
fields = ('title', 'url')
class
BasicSerializer
(
serializers
.
HyperlinkedModelSerializer
):
class
Meta
:
model
=
BasicModel
#
class BasicSerializer(serializers.HyperlinkedModelSerializer):
#
class Meta:
#
model = BasicModel
class
AnchorSerializer
(
serializers
.
HyperlinkedModelSerializer
):
class
Meta
:
model
=
Anchor
#
class AnchorSerializer(serializers.HyperlinkedModelSerializer):
#
class Meta:
#
model = Anchor
class
ManyToManySerializer
(
serializers
.
HyperlinkedModelSerializer
):
class
Meta
:
model
=
ManyToManyModel
#
class ManyToManySerializer(serializers.HyperlinkedModelSerializer):
#
class Meta:
#
model = ManyToManyModel
class
BlogPostSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
BlogPost
#
class BlogPostSerializer(serializers.ModelSerializer):
#
class Meta:
#
model = BlogPost
class
OptionalRelationSerializer
(
serializers
.
HyperlinkedModelSerializer
):
class
Meta
:
model
=
OptionalRelationModel
#
class OptionalRelationSerializer(serializers.HyperlinkedModelSerializer):
#
class Meta:
#
model = OptionalRelationModel
class
BasicList
(
generics
.
ListCreateAPIView
):
queryset
=
BasicModel
.
objects
.
all
()
serializer_class
=
BasicSerializer
#
class BasicList(generics.ListCreateAPIView):
#
queryset = BasicModel.objects.all()
#
serializer_class = BasicSerializer
class
BasicDetail
(
generics
.
RetrieveUpdateDestroyAPIView
):
queryset
=
BasicModel
.
objects
.
all
()
serializer_class
=
BasicSerializer
#
class BasicDetail(generics.RetrieveUpdateDestroyAPIView):
#
queryset = BasicModel.objects.all()
#
serializer_class = BasicSerializer
class
AnchorDetail
(
generics
.
RetrieveAPIView
):
queryset
=
Anchor
.
objects
.
all
()
serializer_class
=
AnchorSerializer
#
class AnchorDetail(generics.RetrieveAPIView):
#
queryset = Anchor.objects.all()
#
serializer_class = AnchorSerializer
class
ManyToManyList
(
generics
.
ListAPIView
):
queryset
=
ManyToManyModel
.
objects
.
all
()
serializer_class
=
ManyToManySerializer
#
class ManyToManyList(generics.ListAPIView):
#
queryset = ManyToManyModel.objects.all()
#
serializer_class = ManyToManySerializer
class
ManyToManyDetail
(
generics
.
RetrieveAPIView
):
queryset
=
ManyToManyModel
.
objects
.
all
()
serializer_class
=
ManyToManySerializer
#
class ManyToManyDetail(generics.RetrieveAPIView):
#
queryset = ManyToManyModel.objects.all()
#
serializer_class = ManyToManySerializer
class
BlogPostCommentListCreate
(
generics
.
ListCreateAPIView
):
queryset
=
BlogPostComment
.
objects
.
all
()
serializer_class
=
BlogPostCommentSerializer
#
class BlogPostCommentListCreate(generics.ListCreateAPIView):
#
queryset = BlogPostComment.objects.all()
#
serializer_class = BlogPostCommentSerializer
class
BlogPostCommentDetail
(
generics
.
RetrieveAPIView
):
queryset
=
BlogPostComment
.
objects
.
all
()
serializer_class
=
BlogPostCommentSerializer
#
class BlogPostCommentDetail(generics.RetrieveAPIView):
#
queryset = BlogPostComment.objects.all()
#
serializer_class = BlogPostCommentSerializer
class
BlogPostDetail
(
generics
.
RetrieveAPIView
):
queryset
=
BlogPost
.
objects
.
all
()
serializer_class
=
BlogPostSerializer
#
class BlogPostDetail(generics.RetrieveAPIView):
#
queryset = BlogPost.objects.all()
#
serializer_class = BlogPostSerializer
class
PhotoListCreate
(
generics
.
ListCreateAPIView
):
queryset
=
Photo
.
objects
.
all
()
serializer_class
=
PhotoSerializer
#
class PhotoListCreate(generics.ListCreateAPIView):
#
queryset = Photo.objects.all()
#
serializer_class = PhotoSerializer
class
AlbumDetail
(
generics
.
RetrieveAPIView
):
queryset
=
Album
.
objects
.
all
()
serializer_class
=
AlbumSerializer
lookup_field
=
'title'
#
class AlbumDetail(generics.RetrieveAPIView):
#
queryset = Album.objects.all()
#
serializer_class = AlbumSerializer
#
lookup_field = 'title'
class
OptionalRelationDetail
(
generics
.
RetrieveUpdateDestroyAPIView
):
queryset
=
OptionalRelationModel
.
objects
.
all
()
serializer_class
=
OptionalRelationSerializer
#
class OptionalRelationDetail(generics.RetrieveUpdateDestroyAPIView):
#
queryset = OptionalRelationModel.objects.all()
#
serializer_class = OptionalRelationSerializer
urlpatterns
=
patterns
(
''
,
url
(
r'^basic/$'
,
BasicList
.
as_view
(),
name
=
'basicmodel-list'
),
url
(
r'^basic/(?P<pk>\d+)/$'
,
BasicDetail
.
as_view
(),
name
=
'basicmodel-detail'
),
url
(
r'^anchor/(?P<pk>\d+)/$'
,
AnchorDetail
.
as_view
(),
name
=
'anchor-detail'
),
url
(
r'^manytomany/$'
,
ManyToManyList
.
as_view
(),
name
=
'manytomanymodel-list'
),
url
(
r'^manytomany/(?P<pk>\d+)/$'
,
ManyToManyDetail
.
as_view
(),
name
=
'manytomanymodel-detail'
),
url
(
r'^posts/(?P<pk>\d+)/$'
,
BlogPostDetail
.
as_view
(),
name
=
'blogpost-detail'
),
url
(
r'^comments/$'
,
BlogPostCommentListCreate
.
as_view
(),
name
=
'blogpostcomment-list'
),
url
(
r'^comments/(?P<pk>\d+)/$'
,
BlogPostCommentDetail
.
as_view
(),
name
=
'blogpostcomment-detail'
),
url
(
r'^albums/(?P<title>\w[\w-]*)/$'
,
AlbumDetail
.
as_view
(),
name
=
'album-detail'
),
url
(
r'^photos/$'
,
PhotoListCreate
.
as_view
(),
name
=
'photo-list'
),
url
(
r'^optionalrelation/(?P<pk>\d+)/$'
,
OptionalRelationDetail
.
as_view
(),
name
=
'optionalrelationmodel-detail'
),
)
class
TestBasicHyperlinkedView
(
TestCase
):
urls
=
'tests.test_hyperlinkedserializers'
def
setUp
(
self
):
"""
Create 3 BasicModel instances.
"""
items
=
[
'foo'
,
'bar'
,
'baz'
]
for
item
in
items
:
BasicModel
(
text
=
item
)
.
save
()
self
.
objects
=
BasicModel
.
objects
self
.
data
=
[
{
'url'
:
'http://testserver/basic/
%
d/'
%
obj
.
id
,
'text'
:
obj
.
text
}
for
obj
in
self
.
objects
.
all
()
]
self
.
list_view
=
BasicList
.
as_view
()
self
.
detail_view
=
BasicDetail
.
as_view
()
def
test_get_list_view
(
self
):
"""
GET requests to ListCreateAPIView should return list of objects.
"""
request
=
factory
.
get
(
'/basic/'
)
response
=
self
.
list_view
(
request
)
.
render
()
self
.
assertEqual
(
response
.
status_code
,
status
.
HTTP_200_OK
)
self
.
assertEqual
(
response
.
data
,
self
.
data
)
def
test_get_detail_view
(
self
):
"""
GET requests to ListCreateAPIView should return list of objects.
"""
request
=
factory
.
get
(
'/basic/1'
)
response
=
self
.
detail_view
(
request
,
pk
=
1
)
.
render
()
self
.
assertEqual
(
response
.
status_code
,
status
.
HTTP_200_OK
)
self
.
assertEqual
(
response
.
data
,
self
.
data
[
0
])
class
TestManyToManyHyperlinkedView
(
TestCase
):
urls
=
'tests.test_hyperlinkedserializers'
def
setUp
(
self
):
"""
Create 3 BasicModel instances.
"""
items
=
[
'foo'
,
'bar'
,
'baz'
]
anchors
=
[]
for
item
in
items
:
anchor
=
Anchor
(
text
=
item
)
anchor
.
save
()
anchors
.
append
(
anchor
)
manytomany
=
ManyToManyModel
()
manytomany
.
save
()
manytomany
.
rel
.
add
(
*
anchors
)
self
.
data
=
[{
'url'
:
'http://testserver/manytomany/1/'
,
'rel'
:
[
'http://testserver/anchor/1/'
,
'http://testserver/anchor/2/'
,
'http://testserver/anchor/3/'
,
]
}]
self
.
list_view
=
ManyToManyList
.
as_view
()
self
.
detail_view
=
ManyToManyDetail
.
as_view
()
def
test_get_list_view
(
self
):
"""
GET requests to ListCreateAPIView should return list of objects.
"""
request
=
factory
.
get
(
'/manytomany/'
)
response
=
self
.
list_view
(
request
)
self
.
assertEqual
(
response
.
status_code
,
status
.
HTTP_200_OK
)
self
.
assertEqual
(
response
.
data
,
self
.
data
)
def
test_get_detail_view
(
self
):
"""
GET requests to ListCreateAPIView should return list of objects.
"""
request
=
factory
.
get
(
'/manytomany/1/'
)
response
=
self
.
detail_view
(
request
,
pk
=
1
)
self
.
assertEqual
(
response
.
status_code
,
status
.
HTTP_200_OK
)
self
.
assertEqual
(
response
.
data
,
self
.
data
[
0
])
class
TestHyperlinkedIdentityFieldLookup
(
TestCase
):
urls
=
'tests.test_hyperlinkedserializers'
def
setUp
(
self
):
"""
Create 3 Album instances.
"""
titles
=
[
'foo'
,
'bar'
,
'baz'
]
for
title
in
titles
:
album
=
Album
(
title
=
title
)
album
.
save
()
self
.
detail_view
=
AlbumDetail
.
as_view
()
self
.
data
=
{
'foo'
:
{
'title'
:
'foo'
,
'url'
:
'http://testserver/albums/foo/'
},
'bar'
:
{
'title'
:
'bar'
,
'url'
:
'http://testserver/albums/bar/'
},
'baz'
:
{
'title'
:
'baz'
,
'url'
:
'http://testserver/albums/baz/'
}
}
def
test_lookup_field
(
self
):
"""
GET requests to AlbumDetail view should return serialized Albums
with a url field keyed by `title`.
"""
for
album
in
Album
.
objects
.
all
():
request
=
factory
.
get
(
'/albums/{0}/'
.
format
(
album
.
title
))
response
=
self
.
detail_view
(
request
,
title
=
album
.
title
)
self
.
assertEqual
(
response
.
status_code
,
status
.
HTTP_200_OK
)
self
.
assertEqual
(
response
.
data
,
self
.
data
[
album
.
title
])
class
TestCreateWithForeignKeys
(
TestCase
):
urls
=
'tests.test_hyperlinkedserializers'
def
setUp
(
self
):
"""
Create a blog post
"""
self
.
post
=
BlogPost
.
objects
.
create
(
title
=
"Test post"
)
self
.
create_view
=
BlogPostCommentListCreate
.
as_view
()
def
test_create_comment
(
self
):
data
=
{
'text'
:
'A test comment'
,
'blog_post_url'
:
'http://testserver/posts/1/'
}
request
=
factory
.
post
(
'/comments/'
,
data
=
data
)
response
=
self
.
create_view
(
request
)
self
.
assertEqual
(
response
.
status_code
,
status
.
HTTP_201_CREATED
)
self
.
assertEqual
(
response
[
'Location'
],
'http://testserver/comments/1/'
)
self
.
assertEqual
(
self
.
post
.
blogpostcomment_set
.
count
(),
1
)
self
.
assertEqual
(
self
.
post
.
blogpostcomment_set
.
all
()[
0
]
.
text
,
'A test comment'
)
class
TestCreateWithForeignKeysAndCustomSlug
(
TestCase
):
urls
=
'tests.test_hyperlinkedserializers'
def
setUp
(
self
):
"""
Create an Album
"""
self
.
post
=
Album
.
objects
.
create
(
title
=
'test-album'
)
self
.
list_create_view
=
PhotoListCreate
.
as_view
()
def
test_create_photo
(
self
):
data
=
{
'description'
:
'A test photo'
,
'album_url'
:
'http://testserver/albums/test-album/'
}
request
=
factory
.
post
(
'/photos/'
,
data
=
data
)
response
=
self
.
list_create_view
(
request
)
self
.
assertEqual
(
response
.
status_code
,
status
.
HTTP_201_CREATED
)
self
.
assertNotIn
(
'Location'
,
response
,
msg
=
'Location should only be included if there is a "url" field on the serializer'
)
self
.
assertEqual
(
self
.
post
.
photo_set
.
count
(),
1
)
self
.
assertEqual
(
self
.
post
.
photo_set
.
all
()[
0
]
.
description
,
'A test photo'
)
class
TestOptionalRelationHyperlinkedView
(
TestCase
):
urls
=
'tests.test_hyperlinkedserializers'
def
setUp
(
self
):
"""
Create 1 OptionalRelationModel instances.
"""
OptionalRelationModel
()
.
save
()
self
.
objects
=
OptionalRelationModel
.
objects
self
.
detail_view
=
OptionalRelationDetail
.
as_view
()
self
.
data
=
{
"url"
:
"http://testserver/optionalrelation/1/"
,
"other"
:
None
}
def
test_get_detail_view
(
self
):
"""
GET requests to RetrieveAPIView with optional relations should return None
for non existing relations.
"""
request
=
factory
.
get
(
'/optionalrelationmodel-detail/1'
)
response
=
self
.
detail_view
(
request
,
pk
=
1
)
self
.
assertEqual
(
response
.
status_code
,
status
.
HTTP_200_OK
)
self
.
assertEqual
(
response
.
data
,
self
.
data
)
def
test_put_detail_view
(
self
):
"""
PUT requests to RetrieveUpdateDestroyAPIView with optional relations
should accept None for non existing relations.
"""
response
=
self
.
client
.
put
(
'/optionalrelation/1/'
,
data
=
json
.
dumps
(
self
.
data
),
content_type
=
'application/json'
)
self
.
assertEqual
(
response
.
status_code
,
status
.
HTTP_200_OK
)
class
TestOverriddenURLField
(
TestCase
):
def
setUp
(
self
):
class
OverriddenURLSerializer
(
serializers
.
HyperlinkedModelSerializer
):
url
=
serializers
.
SerializerMethodField
(
'get_url'
)
class
Meta
:
model
=
BlogPost
fields
=
(
'title'
,
'url'
)
def
get_url
(
self
,
obj
):
return
'foo bar'
self
.
Serializer
=
OverriddenURLSerializer
self
.
obj
=
BlogPost
.
objects
.
create
(
title
=
'New blog post'
)
def
test_overridden_url_field
(
self
):
"""
The 'url' field should respect overriding.
Regression test for #936.
"""
serializer
=
self
.
Serializer
(
self
.
obj
)
self
.
assertEqual
(
serializer
.
data
,
{
'title'
:
'New blog post'
,
'url'
:
'foo bar'
}
)
class
TestURLFieldNameBySettings
(
TestCase
):
urls
=
'tests.test_hyperlinkedserializers'
def
setUp
(
self
):
self
.
saved_url_field_name
=
api_settings
.
URL_FIELD_NAME
api_settings
.
URL_FIELD_NAME
=
'global_url_field'
class
Serializer
(
serializers
.
HyperlinkedModelSerializer
):
class
Meta
:
model
=
BlogPost
fields
=
(
'title'
,
api_settings
.
URL_FIELD_NAME
)
self
.
Serializer
=
Serializer
self
.
obj
=
BlogPost
.
objects
.
create
(
title
=
"New blog post"
)
def
tearDown
(
self
):
api_settings
.
URL_FIELD_NAME
=
self
.
saved_url_field_name
def
test_overridden_url_field_name
(
self
):
request
=
factory
.
get
(
'/posts/'
)
serializer
=
self
.
Serializer
(
self
.
obj
,
context
=
{
'request'
:
request
})
self
.
assertIn
(
api_settings
.
URL_FIELD_NAME
,
serializer
.
data
)
class
TestURLFieldNameByOptions
(
TestCase
):
urls
=
'tests.test_hyperlinkedserializers'
def
setUp
(
self
):
class
Serializer
(
serializers
.
HyperlinkedModelSerializer
):
class
Meta
:
model
=
BlogPost
fields
=
(
'title'
,
'serializer_url_field'
)
url_field_name
=
'serializer_url_field'
self
.
Serializer
=
Serializer
self
.
obj
=
BlogPost
.
objects
.
create
(
title
=
"New blog post"
)
def
test_overridden_url_field_name
(
self
):
request
=
factory
.
get
(
'/posts/'
)
serializer
=
self
.
Serializer
(
self
.
obj
,
context
=
{
'request'
:
request
})
self
.
assertIn
(
self
.
Serializer
.
Meta
.
url_field_name
,
serializer
.
data
)
#
urlpatterns = patterns(
#
'',
#
url(r'^basic/$', BasicList.as_view(), name='basicmodel-list'),
#
url(r'^basic/(?P<pk>\d+)/$', BasicDetail.as_view(), name='basicmodel-detail'),
#
url(r'^anchor/(?P<pk>\d+)/$', AnchorDetail.as_view(), name='anchor-detail'),
#
url(r'^manytomany/$', ManyToManyList.as_view(), name='manytomanymodel-list'),
#
url(r'^manytomany/(?P<pk>\d+)/$', ManyToManyDetail.as_view(), name='manytomanymodel-detail'),
#
url(r'^posts/(?P<pk>\d+)/$', BlogPostDetail.as_view(), name='blogpost-detail'),
#
url(r'^comments/$', BlogPostCommentListCreate.as_view(), name='blogpostcomment-list'),
#
url(r'^comments/(?P<pk>\d+)/$', BlogPostCommentDetail.as_view(), name='blogpostcomment-detail'),
#
url(r'^albums/(?P<title>\w[\w-]*)/$', AlbumDetail.as_view(), name='album-detail'),
#
url(r'^photos/$', PhotoListCreate.as_view(), name='photo-list'),
#
url(r'^optionalrelation/(?P<pk>\d+)/$', OptionalRelationDetail.as_view(), name='optionalrelationmodel-detail'),
#
)
#
class TestBasicHyperlinkedView(TestCase):
#
urls = 'tests.test_hyperlinkedserializers'
#
def setUp(self):
#
"""
#
Create 3 BasicModel instances.
#
"""
#
items = ['foo', 'bar', 'baz']
#
for item in items:
#
BasicModel(text=item).save()
#
self.objects = BasicModel.objects
#
self.data = [
#
{'url': 'http://testserver/basic/%d/' % obj.id, 'text': obj.text}
#
for obj in self.objects.all()
#
]
#
self.list_view = BasicList.as_view()
#
self.detail_view = BasicDetail.as_view()
#
def test_get_list_view(self):
#
"""
#
GET requests to ListCreateAPIView should return list of objects.
#
"""
#
request = factory.get('/basic/')
#
response = self.list_view(request).render()
#
self.assertEqual(response.status_code, status.HTTP_200_OK)
#
self.assertEqual(response.data, self.data)
#
def test_get_detail_view(self):
#
"""
#
GET requests to ListCreateAPIView should return list of objects.
#
"""
#
request = factory.get('/basic/1')
#
response = self.detail_view(request, pk=1).render()
#
self.assertEqual(response.status_code, status.HTTP_200_OK)
#
self.assertEqual(response.data, self.data[0])
#
class TestManyToManyHyperlinkedView(TestCase):
#
urls = 'tests.test_hyperlinkedserializers'
#
def setUp(self):
#
"""
#
Create 3 BasicModel instances.
#
"""
#
items = ['foo', 'bar', 'baz']
#
anchors = []
#
for item in items:
#
anchor = Anchor(text=item)
#
anchor.save()
#
anchors.append(anchor)
#
manytomany = ManyToManyModel()
#
manytomany.save()
#
manytomany.rel.add(*anchors)
#
self.data = [{
#
'url': 'http://testserver/manytomany/1/',
#
'rel': [
#
'http://testserver/anchor/1/',
#
'http://testserver/anchor/2/',
#
'http://testserver/anchor/3/',
#
]
#
}]
#
self.list_view = ManyToManyList.as_view()
#
self.detail_view = ManyToManyDetail.as_view()
#
def test_get_list_view(self):
#
"""
#
GET requests to ListCreateAPIView should return list of objects.
#
"""
#
request = factory.get('/manytomany/')
#
response = self.list_view(request)
#
self.assertEqual(response.status_code, status.HTTP_200_OK)
#
self.assertEqual(response.data, self.data)
#
def test_get_detail_view(self):
#
"""
#
GET requests to ListCreateAPIView should return list of objects.
#
"""
#
request = factory.get('/manytomany/1/')
#
response = self.detail_view(request, pk=1)
#
self.assertEqual(response.status_code, status.HTTP_200_OK)
#
self.assertEqual(response.data, self.data[0])
#
class TestHyperlinkedIdentityFieldLookup(TestCase):
#
urls = 'tests.test_hyperlinkedserializers'
#
def setUp(self):
#
"""
#
Create 3 Album instances.
#
"""
#
titles = ['foo', 'bar', 'baz']
#
for title in titles:
#
album = Album(title=title)
#
album.save()
#
self.detail_view = AlbumDetail.as_view()
#
self.data = {
#
'foo': {'title': 'foo', 'url': 'http://testserver/albums/foo/'},
#
'bar': {'title': 'bar', 'url': 'http://testserver/albums/bar/'},
#
'baz': {'title': 'baz', 'url': 'http://testserver/albums/baz/'}
#
}
#
def test_lookup_field(self):
#
"""
#
GET requests to AlbumDetail view should return serialized Albums
#
with a url field keyed by `title`.
#
"""
#
for album in Album.objects.all():
#
request = factory.get('/albums/{0}/'.format(album.title))
#
response = self.detail_view(request, title=album.title)
#
self.assertEqual(response.status_code, status.HTTP_200_OK)
#
self.assertEqual(response.data, self.data[album.title])
#
class TestCreateWithForeignKeys(TestCase):
#
urls = 'tests.test_hyperlinkedserializers'
#
def setUp(self):
#
"""
#
Create a blog post
#
"""
#
self.post = BlogPost.objects.create(title="Test post")
#
self.create_view = BlogPostCommentListCreate.as_view()
#
def test_create_comment(self):
#
data = {
#
'text': 'A test comment',
#
'blog_post_url': 'http://testserver/posts/1/'
#
}
#
request = factory.post('/comments/', data=data)
#
response = self.create_view(request)
#
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
#
self.assertEqual(response['Location'], 'http://testserver/comments/1/')
#
self.assertEqual(self.post.blogpostcomment_set.count(), 1)
#
self.assertEqual(self.post.blogpostcomment_set.all()[0].text, 'A test comment')
#
class TestCreateWithForeignKeysAndCustomSlug(TestCase):
#
urls = 'tests.test_hyperlinkedserializers'
#
def setUp(self):
#
"""
#
Create an Album
#
"""
#
self.post = Album.objects.create(title='test-album')
#
self.list_create_view = PhotoListCreate.as_view()
#
def test_create_photo(self):
#
data = {
#
'description': 'A test photo',
#
'album_url': 'http://testserver/albums/test-album/'
#
}
#
request = factory.post('/photos/', data=data)
#
response = self.list_create_view(request)
#
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
#
self.assertNotIn('Location', response, msg='Location should only be included if there is a "url" field on the serializer')
#
self.assertEqual(self.post.photo_set.count(), 1)
#
self.assertEqual(self.post.photo_set.all()[0].description, 'A test photo')
#
class TestOptionalRelationHyperlinkedView(TestCase):
#
urls = 'tests.test_hyperlinkedserializers'
#
def setUp(self):
#
"""
#
Create 1 OptionalRelationModel instances.
#
"""
#
OptionalRelationModel().save()
#
self.objects = OptionalRelationModel.objects
#
self.detail_view = OptionalRelationDetail.as_view()
#
self.data = {"url": "http://testserver/optionalrelation/1/", "other": None}
#
def test_get_detail_view(self):
#
"""
#
GET requests to RetrieveAPIView with optional relations should return None
#
for non existing relations.
#
"""
#
request = factory.get('/optionalrelationmodel-detail/1')
#
response = self.detail_view(request, pk=1)
#
self.assertEqual(response.status_code, status.HTTP_200_OK)
#
self.assertEqual(response.data, self.data)
#
def test_put_detail_view(self):
#
"""
#
PUT requests to RetrieveUpdateDestroyAPIView with optional relations
#
should accept None for non existing relations.
#
"""
#
response = self.client.put('/optionalrelation/1/',
#
data=json.dumps(self.data),
#
content_type='application/json')
#
self.assertEqual(response.status_code, status.HTTP_200_OK)
#
class TestOverriddenURLField(TestCase):
#
def setUp(self):
#
class OverriddenURLSerializer(serializers.HyperlinkedModelSerializer):
#
url = serializers.SerializerMethodField('get_url')
#
class Meta:
#
model = BlogPost
#
fields = ('title', 'url')
#
def get_url(self, obj):
#
return 'foo bar'
#
self.Serializer = OverriddenURLSerializer
#
self.obj = BlogPost.objects.create(title='New blog post')
#
def test_overridden_url_field(self):
#
"""
#
The 'url' field should respect overriding.
#
Regression test for #936.
#
"""
#
serializer = self.Serializer(self.obj)
#
self.assertEqual(
#
serializer.data,
#
{'title': 'New blog post', 'url': 'foo bar'}
#
)
#
class TestURLFieldNameBySettings(TestCase):
#
urls = 'tests.test_hyperlinkedserializers'
#
def setUp(self):
#
self.saved_url_field_name = api_settings.URL_FIELD_NAME
#
api_settings.URL_FIELD_NAME = 'global_url_field'
#
class Serializer(serializers.HyperlinkedModelSerializer):
#
class Meta:
#
model = BlogPost
#
fields = ('title', api_settings.URL_FIELD_NAME)
#
self.Serializer = Serializer
#
self.obj = BlogPost.objects.create(title="New blog post")
#
def tearDown(self):
#
api_settings.URL_FIELD_NAME = self.saved_url_field_name
#
def test_overridden_url_field_name(self):
#
request = factory.get('/posts/')
#
serializer = self.Serializer(self.obj, context={'request': request})
#
self.assertIn(api_settings.URL_FIELD_NAME, serializer.data)
#
class TestURLFieldNameByOptions(TestCase):
#
urls = 'tests.test_hyperlinkedserializers'
#
def setUp(self):
#
class Serializer(serializers.HyperlinkedModelSerializer):
#
class Meta:
#
model = BlogPost
#
fields = ('title', 'serializer_url_field')
#
url_field_name = 'serializer_url_field'
#
self.Serializer = Serializer
#
self.obj = BlogPost.objects.create(title="New blog post")
#
def test_overridden_url_field_name(self):
#
request = factory.get('/posts/')
#
serializer = self.Serializer(self.obj, context={'request': request})
#
self.assertIn(self.Serializer.Meta.url_field_name, serializer.data)
tests/test_nullable_fields.py
View file @
f2852811
from
django.core.urlresolvers
import
reverse
#
from django.core.urlresolvers import reverse
from
django.conf.urls
import
patterns
,
url
from
rest_framework
import
serializers
,
generics
from
rest_framework.test
import
APITestCase
from
tests.models
import
NullableForeignKeySource
#
from django.conf.urls import patterns, url
#
from rest_framework import serializers, generics
#
from rest_framework.test import APITestCase
#
from tests.models import NullableForeignKeySource
class
NullableFKSourceSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
NullableForeignKeySource
#
class NullableFKSourceSerializer(serializers.ModelSerializer):
#
class Meta:
#
model = NullableForeignKeySource
class
NullableFKSourceDetail
(
generics
.
RetrieveUpdateDestroyAPIView
):
queryset
=
NullableForeignKeySource
.
objects
.
all
()
serializer_class
=
NullableFKSourceSerializer
#
class NullableFKSourceDetail(generics.RetrieveUpdateDestroyAPIView):
#
queryset = NullableForeignKeySource.objects.all()
#
serializer_class = NullableFKSourceSerializer
urlpatterns
=
patterns
(
''
,
url
(
r'^objects/(?P<pk>\d+)/$'
,
NullableFKSourceDetail
.
as_view
(),
name
=
'object-detail'
),
)
#
urlpatterns = patterns(
#
'',
#
url(r'^objects/(?P<pk>\d+)/$', NullableFKSourceDetail.as_view(), name='object-detail'),
#
)
class
NullableForeignKeyTests
(
APITestCase
):
"""
DRF should be able to handle nullable foreign keys when a test
Client POST/PUT request is made with its own serialized object.
"""
urls
=
'tests.test_nullable_fields'
#
class NullableForeignKeyTests(APITestCase):
#
"""
#
DRF should be able to handle nullable foreign keys when a test
#
Client POST/PUT request is made with its own serialized object.
#
"""
#
urls = 'tests.test_nullable_fields'
def
test_updating_object_with_null_fk
(
self
):
obj
=
NullableForeignKeySource
(
name
=
'example'
,
target
=
None
)
obj
.
save
()
serialized_data
=
NullableFKSourceSerializer
(
obj
)
.
data
#
def test_updating_object_with_null_fk(self):
#
obj = NullableForeignKeySource(name='example', target=None)
#
obj.save()
#
serialized_data = NullableFKSourceSerializer(obj).data
response
=
self
.
client
.
put
(
reverse
(
'object-detail'
,
args
=
[
obj
.
pk
]),
serialized_data
)
#
response = self.client.put(reverse('object-detail', args=[obj.pk]), serialized_data)
self
.
assertEqual
(
response
.
data
,
serialized_data
)
#
self.assertEqual(response.data, serialized_data)
tests/test_pagination.py
View file @
f2852811
...
...
@@ -391,10 +391,10 @@ class CustomField(serializers.Field):
class
BasicModelSerializer
(
serializers
.
Serializer
):
text
=
CustomField
()
def
__init__
(
self
,
*
args
,
**
kwargs
):
super
(
BasicModelSerializer
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
def
to_native
(
self
,
value
):
if
'view'
not
in
self
.
context
:
raise
RuntimeError
(
"context isn't getting passed into serializer init"
)
raise
RuntimeError
(
"context isn't getting passed into serializer"
)
return
super
(
BasicSerializer
,
self
)
.
to_native
(
value
)
class
TestContextPassedToCustomField
(
TestCase
):
...
...
@@ -423,7 +423,7 @@ class LinksSerializer(serializers.Serializer):
class
CustomPaginationSerializer
(
pagination
.
BasePaginationSerializer
):
links
=
LinksSerializer
(
source
=
'*'
)
# Takes the page object as the source
total_results
=
serializers
.
Field
(
source
=
'paginator.count'
)
total_results
=
serializers
.
ReadOnly
Field
(
source
=
'paginator.count'
)
results_field
=
'objects'
...
...
tests/test_permissions.py
View file @
f2852811
...
...
@@ -108,59 +108,59 @@ class ModelPermissionsIntegrationTests(TestCase):
response
=
instance_view
(
request
,
pk
=
'2'
)
self
.
assertEqual
(
response
.
status_code
,
status
.
HTTP_403_FORBIDDEN
)
def
test_options_permitted
(
self
):
request
=
factory
.
options
(
'/'
,
HTTP_AUTHORIZATION
=
self
.
permitted_credentials
)
response
=
root_view
(
request
,
pk
=
'1'
)
self
.
assertEqual
(
response
.
status_code
,
status
.
HTTP_200_OK
)
self
.
assertIn
(
'actions'
,
response
.
data
)
self
.
assertEqual
(
list
(
response
.
data
[
'actions'
]
.
keys
()),
[
'POST'
])
request
=
factory
.
options
(
'/1'
,
HTTP_AUTHORIZATION
=
self
.
permitted_credentials
)
response
=
instance_view
(
request
,
pk
=
'1'
)
self
.
assertEqual
(
response
.
status_code
,
status
.
HTTP_200_OK
)
self
.
assertIn
(
'actions'
,
response
.
data
)
self
.
assertEqual
(
list
(
response
.
data
[
'actions'
]
.
keys
()),
[
'PUT'
])
def
test_options_disallowed
(
self
):
request
=
factory
.
options
(
'/'
,
HTTP_AUTHORIZATION
=
self
.
disallowed_credentials
)
response
=
root_view
(
request
,
pk
=
'1'
)
self
.
assertEqual
(
response
.
status_code
,
status
.
HTTP_200_OK
)
self
.
assertNotIn
(
'actions'
,
response
.
data
)
request
=
factory
.
options
(
'/1'
,
HTTP_AUTHORIZATION
=
self
.
disallowed_credentials
)
response
=
instance_view
(
request
,
pk
=
'1'
)
self
.
assertEqual
(
response
.
status_code
,
status
.
HTTP_200_OK
)
self
.
assertNotIn
(
'actions'
,
response
.
data
)
def
test_options_updateonly
(
self
):
request
=
factory
.
options
(
'/'
,
HTTP_AUTHORIZATION
=
self
.
updateonly_credentials
)
response
=
root_view
(
request
,
pk
=
'1'
)
self
.
assertEqual
(
response
.
status_code
,
status
.
HTTP_200_OK
)
self
.
assertNotIn
(
'actions'
,
response
.
data
)
request
=
factory
.
options
(
'/1'
,
HTTP_AUTHORIZATION
=
self
.
updateonly_credentials
)
response
=
instance_view
(
request
,
pk
=
'1'
)
self
.
assertEqual
(
response
.
status_code
,
status
.
HTTP_200_OK
)
self
.
assertIn
(
'actions'
,
response
.
data
)
self
.
assertEqual
(
list
(
response
.
data
[
'actions'
]
.
keys
()),
[
'PUT'
])
#
def test_options_permitted(self):
#
request = factory.options(
#
'/',
#
HTTP_AUTHORIZATION=self.permitted_credentials
#
)
#
response = root_view(request, pk='1')
#
self.assertEqual(response.status_code, status.HTTP_200_OK)
#
self.assertIn('actions', response.data)
#
self.assertEqual(list(response.data['actions'].keys()), ['POST'])
#
request = factory.options(
#
'/1',
#
HTTP_AUTHORIZATION=self.permitted_credentials
#
)
#
response = instance_view(request, pk='1')
#
self.assertEqual(response.status_code, status.HTTP_200_OK)
#
self.assertIn('actions', response.data)
#
self.assertEqual(list(response.data['actions'].keys()), ['PUT'])
#
def test_options_disallowed(self):
#
request = factory.options(
#
'/',
#
HTTP_AUTHORIZATION=self.disallowed_credentials
#
)
#
response = root_view(request, pk='1')
#
self.assertEqual(response.status_code, status.HTTP_200_OK)
#
self.assertNotIn('actions', response.data)
#
request = factory.options(
#
'/1',
#
HTTP_AUTHORIZATION=self.disallowed_credentials
#
)
#
response = instance_view(request, pk='1')
#
self.assertEqual(response.status_code, status.HTTP_200_OK)
#
self.assertNotIn('actions', response.data)
#
def test_options_updateonly(self):
#
request = factory.options(
#
'/',
#
HTTP_AUTHORIZATION=self.updateonly_credentials
#
)
#
response = root_view(request, pk='1')
#
self.assertEqual(response.status_code, status.HTTP_200_OK)
#
self.assertNotIn('actions', response.data)
#
request = factory.options(
#
'/1',
#
HTTP_AUTHORIZATION=self.updateonly_credentials
#
)
#
response = instance_view(request, pk='1')
#
self.assertEqual(response.status_code, status.HTTP_200_OK)
#
self.assertIn('actions', response.data)
#
self.assertEqual(list(response.data['actions'].keys()), ['PUT'])
class
BasicPermModel
(
models
.
Model
):
...
...
tests/test_relations.py
View file @
f2852811
"""
General tests for relational fields.
"""
from
__future__
import
unicode_literals
from
django
import
get_version
from
django.db
import
models
from
django.test
import
TestCase
from
django.utils
import
unittest
from
rest_framework
import
serializers
from
tests.models
import
BlogPost
class
NullModel
(
models
.
Model
):
pass
class
FieldTests
(
TestCase
):
def
test_pk_related_field_with_empty_string
(
self
):
"""
Regression test for #446
https://github.com/tomchristie/django-rest-framework/issues/446
"""
field
=
serializers
.
PrimaryKeyRelatedField
(
queryset
=
NullModel
.
objects
.
all
())
self
.
assertRaises
(
serializers
.
ValidationError
,
field
.
from_native
,
''
)
self
.
assertRaises
(
serializers
.
ValidationError
,
field
.
from_native
,
[])
def
test_hyperlinked_related_field_with_empty_string
(
self
):
field
=
serializers
.
HyperlinkedRelatedField
(
queryset
=
NullModel
.
objects
.
all
(),
view_name
=
''
)
self
.
assertRaises
(
serializers
.
ValidationError
,
field
.
from_native
,
''
)
self
.
assertRaises
(
serializers
.
ValidationError
,
field
.
from_native
,
[])
def
test_slug_related_field_with_empty_string
(
self
):
field
=
serializers
.
SlugRelatedField
(
queryset
=
NullModel
.
objects
.
all
(),
slug_field
=
'pk'
)
self
.
assertRaises
(
serializers
.
ValidationError
,
field
.
from_native
,
''
)
self
.
assertRaises
(
serializers
.
ValidationError
,
field
.
from_native
,
[])
class
TestManyRelatedMixin
(
TestCase
):
def
test_missing_many_to_many_related_field
(
self
):
'''
Regression test for #632
https://github.com/tomchristie/django-rest-framework/pull/632
'''
field
=
serializers
.
RelatedField
(
many
=
True
,
read_only
=
False
)
into
=
{}
field
.
field_from_native
({},
None
,
'field_name'
,
into
)
self
.
assertEqual
(
into
[
'field_name'
],
[])
# Regression tests for #694 (`source` attribute on related fields)
class
RelatedFieldSourceTests
(
TestCase
):
def
test_related_manager_source
(
self
):
"""
Relational fields should be able to use manager-returning methods as their source.
"""
BlogPost
.
objects
.
create
(
title
=
'blah'
)
field
=
serializers
.
RelatedField
(
many
=
True
,
source
=
'get_blogposts_manager'
)
class
ClassWithManagerMethod
(
object
):
def
get_blogposts_manager
(
self
):
return
BlogPost
.
objects
obj
=
ClassWithManagerMethod
()
value
=
field
.
field_to_native
(
obj
,
'field_name'
)
self
.
assertEqual
(
value
,
[
'BlogPost object'
])
def
test_related_queryset_source
(
self
):
"""
Relational fields should be able to use queryset-returning methods as their source.
"""
BlogPost
.
objects
.
create
(
title
=
'blah'
)
field
=
serializers
.
RelatedField
(
many
=
True
,
source
=
'get_blogposts_queryset'
)
class
ClassWithQuerysetMethod
(
object
):
def
get_blogposts_queryset
(
self
):
return
BlogPost
.
objects
.
all
()
obj
=
ClassWithQuerysetMethod
()
value
=
field
.
field_to_native
(
obj
,
'field_name'
)
self
.
assertEqual
(
value
,
[
'BlogPost object'
])
def
test_dotted_source
(
self
):
"""
Source argument should support dotted.source notation.
"""
BlogPost
.
objects
.
create
(
title
=
'blah'
)
field
=
serializers
.
RelatedField
(
many
=
True
,
source
=
'a.b.c'
)
class
ClassWithQuerysetMethod
(
object
):
a
=
{
'b'
:
{
'c'
:
BlogPost
.
objects
.
all
()
}
}
obj
=
ClassWithQuerysetMethod
()
value
=
field
.
field_to_native
(
obj
,
'field_name'
)
self
.
assertEqual
(
value
,
[
'BlogPost object'
])
# Regression for #1129
def
test_exception_for_incorect_fk
(
self
):
"""
Check that the exception message are correct if the source field
doesn't exist.
"""
from
tests.models
import
ManyToManySource
class
Meta
:
model
=
ManyToManySource
attrs
=
{
'name'
:
serializers
.
SlugRelatedField
(
slug_field
=
'name'
,
source
=
'banzai'
),
'Meta'
:
Meta
,
}
TestSerializer
=
type
(
str
(
'TestSerializer'
),
(
serializers
.
ModelSerializer
,),
attrs
)
with
self
.
assertRaises
(
AttributeError
):
TestSerializer
(
data
=
{
'name'
:
'foo'
})
@unittest.skipIf
(
get_version
()
<
'1.6.0'
,
'Upstream behaviour changed in v1.6'
)
class
RelatedFieldChoicesTests
(
TestCase
):
"""
Tests for #1408 "Web browseable API doesn't have blank option on drop down list box"
https://github.com/tomchristie/django-rest-framework/issues/1408
"""
def
test_blank_option_is_added_to_choice_if_required_equals_false
(
self
):
"""
"""
post
=
BlogPost
(
title
=
"Checking blank option is added"
)
post
.
save
()
queryset
=
BlogPost
.
objects
.
all
()
field
=
serializers
.
RelatedField
(
required
=
False
,
queryset
=
queryset
)
choice_count
=
BlogPost
.
objects
.
count
()
widget_count
=
len
(
field
.
widget
.
choices
)
self
.
assertEqual
(
widget_count
,
choice_count
+
1
,
'BLANK_CHOICE_DASH option should have been added'
)
#
"""
#
General tests for relational fields.
#
"""
#
from __future__ import unicode_literals
#
from django import get_version
#
from django.db import models
#
from django.test import TestCase
#
from django.utils import unittest
#
from rest_framework import serializers
#
from tests.models import BlogPost
#
class NullModel(models.Model):
#
pass
#
class FieldTests(TestCase):
#
def test_pk_related_field_with_empty_string(self):
#
"""
#
Regression test for #446
#
https://github.com/tomchristie/django-rest-framework/issues/446
#
"""
#
field = serializers.PrimaryKeyRelatedField(queryset=NullModel.objects.all())
#
self.assertRaises(serializers.ValidationError, field.from_native, '')
#
self.assertRaises(serializers.ValidationError, field.from_native, [])
#
def test_hyperlinked_related_field_with_empty_string(self):
#
field = serializers.HyperlinkedRelatedField(queryset=NullModel.objects.all(), view_name='')
#
self.assertRaises(serializers.ValidationError, field.from_native, '')
#
self.assertRaises(serializers.ValidationError, field.from_native, [])
#
def test_slug_related_field_with_empty_string(self):
#
field = serializers.SlugRelatedField(queryset=NullModel.objects.all(), slug_field='pk')
#
self.assertRaises(serializers.ValidationError, field.from_native, '')
#
self.assertRaises(serializers.ValidationError, field.from_native, [])
#
class TestManyRelatedMixin(TestCase):
#
def test_missing_many_to_many_related_field(self):
#
'''
#
Regression test for #632
#
https://github.com/tomchristie/django-rest-framework/pull/632
#
'''
#
field = serializers.RelatedField(many=True, read_only=False)
#
into = {}
#
field.field_from_native({}, None, 'field_name', into)
#
self.assertEqual(into['field_name'], [])
#
#
Regression tests for #694 (`source` attribute on related fields)
#
class RelatedFieldSourceTests(TestCase):
#
def test_related_manager_source(self):
#
"""
#
Relational fields should be able to use manager-returning methods as their source.
#
"""
#
BlogPost.objects.create(title='blah')
#
field = serializers.RelatedField(many=True, source='get_blogposts_manager')
#
class ClassWithManagerMethod(object):
#
def get_blogposts_manager(self):
#
return BlogPost.objects
#
obj = ClassWithManagerMethod()
#
value = field.field_to_native(obj, 'field_name')
#
self.assertEqual(value, ['BlogPost object'])
#
def test_related_queryset_source(self):
#
"""
#
Relational fields should be able to use queryset-returning methods as their source.
#
"""
#
BlogPost.objects.create(title='blah')
#
field = serializers.RelatedField(many=True, source='get_blogposts_queryset')
#
class ClassWithQuerysetMethod(object):
#
def get_blogposts_queryset(self):
#
return BlogPost.objects.all()
#
obj = ClassWithQuerysetMethod()
#
value = field.field_to_native(obj, 'field_name')
#
self.assertEqual(value, ['BlogPost object'])
#
def test_dotted_source(self):
#
"""
#
Source argument should support dotted.source notation.
#
"""
#
BlogPost.objects.create(title='blah')
#
field = serializers.RelatedField(many=True, source='a.b.c')
#
class ClassWithQuerysetMethod(object):
#
a = {
#
'b': {
#
'c': BlogPost.objects.all()
#
}
#
}
#
obj = ClassWithQuerysetMethod()
#
value = field.field_to_native(obj, 'field_name')
#
self.assertEqual(value, ['BlogPost object'])
#
# Regression for #1129
#
def test_exception_for_incorect_fk(self):
#
"""
#
Check that the exception message are correct if the source field
#
doesn't exist.
#
"""
#
from tests.models import ManyToManySource
#
class Meta:
#
model = ManyToManySource
#
attrs = {
#
'name': serializers.SlugRelatedField(
#
slug_field='name', source='banzai'),
#
'Meta': Meta,
#
}
#
TestSerializer = type(
#
str('TestSerializer'),
#
(serializers.ModelSerializer,),
#
attrs
#
)
#
with self.assertRaises(AttributeError):
#
TestSerializer(data={'name': 'foo'})
#
@unittest.skipIf(get_version() < '1.6.0', 'Upstream behaviour changed in v1.6')
#
class RelatedFieldChoicesTests(TestCase):
#
"""
#
Tests for #1408 "Web browseable API doesn't have blank option on drop down list box"
#
https://github.com/tomchristie/django-rest-framework/issues/1408
#
"""
#
def test_blank_option_is_added_to_choice_if_required_equals_false(self):
#
"""
#
"""
#
post = BlogPost(title="Checking blank option is added")
#
post.save()
#
queryset = BlogPost.objects.all()
#
field = serializers.RelatedField(required=False, queryset=queryset)
#
choice_count = BlogPost.objects.count()
#
widget_count = len(field.widget.choices)
#
self.assertEqual(widget_count, choice_count + 1, 'BLANK_CHOICE_DASH option should have been added')
tests/test_relations_hyperlink.py
View file @
f2852811
from
__future__
import
unicode_literals
from
django.conf.urls
import
patterns
,
url
from
django.test
import
TestCase
from
rest_framework
import
serializers
from
rest_framework.test
import
APIRequestFactory
from
tests.models
import
(
BlogPost
,
ManyToManyTarget
,
ManyToManySource
,
ForeignKeyTarget
,
ForeignKeySource
,
NullableForeignKeySource
,
OneToOneTarget
,
NullableOneToOneSource
)
factory
=
APIRequestFactory
()
request
=
factory
.
get
(
'/'
)
# Just to ensure we have a request in the serializer context
def
dummy_view
(
request
,
pk
):
pass
urlpatterns
=
patterns
(
''
,
url
(
r'^dummyurl/(?P<pk>[0-9]+)/$'
,
dummy_view
,
name
=
'dummy-url'
),
url
(
r'^manytomanysource/(?P<pk>[0-9]+)/$'
,
dummy_view
,
name
=
'manytomanysource-detail'
),
url
(
r'^manytomanytarget/(?P<pk>[0-9]+)/$'
,
dummy_view
,
name
=
'manytomanytarget-detail'
),
url
(
r'^foreignkeysource/(?P<pk>[0-9]+)/$'
,
dummy_view
,
name
=
'foreignkeysource-detail'
),
url
(
r'^foreignkeytarget/(?P<pk>[0-9]+)/$'
,
dummy_view
,
name
=
'foreignkeytarget-detail'
),
url
(
r'^nullableforeignkeysource/(?P<pk>[0-9]+)/$'
,
dummy_view
,
name
=
'nullableforeignkeysource-detail'
),
url
(
r'^onetoonetarget/(?P<pk>[0-9]+)/$'
,
dummy_view
,
name
=
'onetoonetarget-detail'
),
url
(
r'^nullableonetoonesource/(?P<pk>[0-9]+)/$'
,
dummy_view
,
name
=
'nullableonetoonesource-detail'
),
)
# ManyToMany
class
ManyToManyTargetSerializer
(
serializers
.
HyperlinkedModelSerializer
):
class
Meta
:
model
=
ManyToManyTarget
fields
=
(
'url'
,
'name'
,
'sources'
)
class
ManyToManySourceSerializer
(
serializers
.
HyperlinkedModelSerializer
):
class
Meta
:
model
=
ManyToManySource
fields
=
(
'url'
,
'name'
,
'targets'
)
# ForeignKey
class
ForeignKeyTargetSerializer
(
serializers
.
HyperlinkedModelSerializer
):
class
Meta
:
model
=
ForeignKeyTarget
fields
=
(
'url'
,
'name'
,
'sources'
)
class
ForeignKeySourceSerializer
(
serializers
.
HyperlinkedModelSerializer
):
class
Meta
:
model
=
ForeignKeySource
fields
=
(
'url'
,
'name'
,
'target'
)
# Nullable ForeignKey
class
NullableForeignKeySourceSerializer
(
serializers
.
HyperlinkedModelSerializer
):
class
Meta
:
model
=
NullableForeignKeySource
fields
=
(
'url'
,
'name'
,
'target'
)
# Nullable OneToOne
class
NullableOneToOneTargetSerializer
(
serializers
.
HyperlinkedModelSerializer
):
class
Meta
:
model
=
OneToOneTarget
fields
=
(
'url'
,
'name'
,
'nullable_source'
)
# TODO: Add test that .data cannot be accessed prior to .is_valid
class
HyperlinkedManyToManyTests
(
TestCase
):
urls
=
'tests.test_relations_hyperlink'
def
setUp
(
self
):
for
idx
in
range
(
1
,
4
):
target
=
ManyToManyTarget
(
name
=
'target-
%
d'
%
idx
)
target
.
save
()
source
=
ManyToManySource
(
name
=
'source-
%
d'
%
idx
)
source
.
save
()
for
target
in
ManyToManyTarget
.
objects
.
all
():
source
.
targets
.
add
(
target
)
def
test_many_to_many_retrieve
(
self
):
queryset
=
ManyToManySource
.
objects
.
all
()
serializer
=
ManyToManySourceSerializer
(
queryset
,
many
=
True
,
context
=
{
'request'
:
request
})
expected
=
[
{
'url'
:
'http://testserver/manytomanysource/1/'
,
'name'
:
'source-1'
,
'targets'
:
[
'http://testserver/manytomanytarget/1/'
]},
{
'url'
:
'http://testserver/manytomanysource/2/'
,
'name'
:
'source-2'
,
'targets'
:
[
'http://testserver/manytomanytarget/1/'
,
'http://testserver/manytomanytarget/2/'
]},
{
'url'
:
'http://testserver/manytomanysource/3/'
,
'name'
:
'source-3'
,
'targets'
:
[
'http://testserver/manytomanytarget/1/'
,
'http://testserver/manytomanytarget/2/'
,
'http://testserver/manytomanytarget/3/'
]}
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
def
test_reverse_many_to_many_retrieve
(
self
):
queryset
=
ManyToManyTarget
.
objects
.
all
()
serializer
=
ManyToManyTargetSerializer
(
queryset
,
many
=
True
,
context
=
{
'request'
:
request
})
expected
=
[
{
'url'
:
'http://testserver/manytomanytarget/1/'
,
'name'
:
'target-1'
,
'sources'
:
[
'http://testserver/manytomanysource/1/'
,
'http://testserver/manytomanysource/2/'
,
'http://testserver/manytomanysource/3/'
]},
{
'url'
:
'http://testserver/manytomanytarget/2/'
,
'name'
:
'target-2'
,
'sources'
:
[
'http://testserver/manytomanysource/2/'
,
'http://testserver/manytomanysource/3/'
]},
{
'url'
:
'http://testserver/manytomanytarget/3/'
,
'name'
:
'target-3'
,
'sources'
:
[
'http://testserver/manytomanysource/3/'
]}
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
def
test_many_to_many_update
(
self
):
data
=
{
'url'
:
'http://testserver/manytomanysource/1/'
,
'name'
:
'source-1'
,
'targets'
:
[
'http://testserver/manytomanytarget/1/'
,
'http://testserver/manytomanytarget/2/'
,
'http://testserver/manytomanytarget/3/'
]}
instance
=
ManyToManySource
.
objects
.
get
(
pk
=
1
)
serializer
=
ManyToManySourceSerializer
(
instance
,
data
=
data
,
context
=
{
'request'
:
request
})
self
.
assertTrue
(
serializer
.
is_valid
())
serializer
.
save
()
self
.
assertEqual
(
serializer
.
data
,
data
)
# Ensure source 1 is updated, and everything else is as expected
queryset
=
ManyToManySource
.
objects
.
all
()
serializer
=
ManyToManySourceSerializer
(
queryset
,
many
=
True
,
context
=
{
'request'
:
request
})
expected
=
[
{
'url'
:
'http://testserver/manytomanysource/1/'
,
'name'
:
'source-1'
,
'targets'
:
[
'http://testserver/manytomanytarget/1/'
,
'http://testserver/manytomanytarget/2/'
,
'http://testserver/manytomanytarget/3/'
]},
{
'url'
:
'http://testserver/manytomanysource/2/'
,
'name'
:
'source-2'
,
'targets'
:
[
'http://testserver/manytomanytarget/1/'
,
'http://testserver/manytomanytarget/2/'
]},
{
'url'
:
'http://testserver/manytomanysource/3/'
,
'name'
:
'source-3'
,
'targets'
:
[
'http://testserver/manytomanytarget/1/'
,
'http://testserver/manytomanytarget/2/'
,
'http://testserver/manytomanytarget/3/'
]}
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
def
test_reverse_many_to_many_update
(
self
):
data
=
{
'url'
:
'http://testserver/manytomanytarget/1/'
,
'name'
:
'target-1'
,
'sources'
:
[
'http://testserver/manytomanysource/1/'
]}
instance
=
ManyToManyTarget
.
objects
.
get
(
pk
=
1
)
serializer
=
ManyToManyTargetSerializer
(
instance
,
data
=
data
,
context
=
{
'request'
:
request
})
self
.
assertTrue
(
serializer
.
is_valid
())
serializer
.
save
()
self
.
assertEqual
(
serializer
.
data
,
data
)
# Ensure target 1 is updated, and everything else is as expected
queryset
=
ManyToManyTarget
.
objects
.
all
()
serializer
=
ManyToManyTargetSerializer
(
queryset
,
many
=
True
,
context
=
{
'request'
:
request
})
expected
=
[
{
'url'
:
'http://testserver/manytomanytarget/1/'
,
'name'
:
'target-1'
,
'sources'
:
[
'http://testserver/manytomanysource/1/'
]},
{
'url'
:
'http://testserver/manytomanytarget/2/'
,
'name'
:
'target-2'
,
'sources'
:
[
'http://testserver/manytomanysource/2/'
,
'http://testserver/manytomanysource/3/'
]},
{
'url'
:
'http://testserver/manytomanytarget/3/'
,
'name'
:
'target-3'
,
'sources'
:
[
'http://testserver/manytomanysource/3/'
]}
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
def
test_many_to_many_create
(
self
):
data
=
{
'url'
:
'http://testserver/manytomanysource/4/'
,
'name'
:
'source-4'
,
'targets'
:
[
'http://testserver/manytomanytarget/1/'
,
'http://testserver/manytomanytarget/3/'
]}
serializer
=
ManyToManySourceSerializer
(
data
=
data
,
context
=
{
'request'
:
request
})
self
.
assertTrue
(
serializer
.
is_valid
())
obj
=
serializer
.
save
()
self
.
assertEqual
(
serializer
.
data
,
data
)
self
.
assertEqual
(
obj
.
name
,
'source-4'
)
# Ensure source 4 is added, and everything else is as expected
queryset
=
ManyToManySource
.
objects
.
all
()
serializer
=
ManyToManySourceSerializer
(
queryset
,
many
=
True
,
context
=
{
'request'
:
request
})
expected
=
[
{
'url'
:
'http://testserver/manytomanysource/1/'
,
'name'
:
'source-1'
,
'targets'
:
[
'http://testserver/manytomanytarget/1/'
]},
{
'url'
:
'http://testserver/manytomanysource/2/'
,
'name'
:
'source-2'
,
'targets'
:
[
'http://testserver/manytomanytarget/1/'
,
'http://testserver/manytomanytarget/2/'
]},
{
'url'
:
'http://testserver/manytomanysource/3/'
,
'name'
:
'source-3'
,
'targets'
:
[
'http://testserver/manytomanytarget/1/'
,
'http://testserver/manytomanytarget/2/'
,
'http://testserver/manytomanytarget/3/'
]},
{
'url'
:
'http://testserver/manytomanysource/4/'
,
'name'
:
'source-4'
,
'targets'
:
[
'http://testserver/manytomanytarget/1/'
,
'http://testserver/manytomanytarget/3/'
]}
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
def
test_reverse_many_to_many_create
(
self
):
data
=
{
'url'
:
'http://testserver/manytomanytarget/4/'
,
'name'
:
'target-4'
,
'sources'
:
[
'http://testserver/manytomanysource/1/'
,
'http://testserver/manytomanysource/3/'
]}
serializer
=
ManyToManyTargetSerializer
(
data
=
data
,
context
=
{
'request'
:
request
})
self
.
assertTrue
(
serializer
.
is_valid
())
obj
=
serializer
.
save
()
self
.
assertEqual
(
serializer
.
data
,
data
)
self
.
assertEqual
(
obj
.
name
,
'target-4'
)
# Ensure target 4 is added, and everything else is as expected
queryset
=
ManyToManyTarget
.
objects
.
all
()
serializer
=
ManyToManyTargetSerializer
(
queryset
,
many
=
True
,
context
=
{
'request'
:
request
})
expected
=
[
{
'url'
:
'http://testserver/manytomanytarget/1/'
,
'name'
:
'target-1'
,
'sources'
:
[
'http://testserver/manytomanysource/1/'
,
'http://testserver/manytomanysource/2/'
,
'http://testserver/manytomanysource/3/'
]},
{
'url'
:
'http://testserver/manytomanytarget/2/'
,
'name'
:
'target-2'
,
'sources'
:
[
'http://testserver/manytomanysource/2/'
,
'http://testserver/manytomanysource/3/'
]},
{
'url'
:
'http://testserver/manytomanytarget/3/'
,
'name'
:
'target-3'
,
'sources'
:
[
'http://testserver/manytomanysource/3/'
]},
{
'url'
:
'http://testserver/manytomanytarget/4/'
,
'name'
:
'target-4'
,
'sources'
:
[
'http://testserver/manytomanysource/1/'
,
'http://testserver/manytomanysource/3/'
]}
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
class
HyperlinkedForeignKeyTests
(
TestCase
):
urls
=
'tests.test_relations_hyperlink'
def
setUp
(
self
):
target
=
ForeignKeyTarget
(
name
=
'target-1'
)
target
.
save
()
new_target
=
ForeignKeyTarget
(
name
=
'target-2'
)
new_target
.
save
()
for
idx
in
range
(
1
,
4
):
source
=
ForeignKeySource
(
name
=
'source-
%
d'
%
idx
,
target
=
target
)
source
.
save
()
def
test_foreign_key_retrieve
(
self
):
queryset
=
ForeignKeySource
.
objects
.
all
()
serializer
=
ForeignKeySourceSerializer
(
queryset
,
many
=
True
,
context
=
{
'request'
:
request
})
expected
=
[
{
'url'
:
'http://testserver/foreignkeysource/1/'
,
'name'
:
'source-1'
,
'target'
:
'http://testserver/foreignkeytarget/1/'
},
{
'url'
:
'http://testserver/foreignkeysource/2/'
,
'name'
:
'source-2'
,
'target'
:
'http://testserver/foreignkeytarget/1/'
},
{
'url'
:
'http://testserver/foreignkeysource/3/'
,
'name'
:
'source-3'
,
'target'
:
'http://testserver/foreignkeytarget/1/'
}
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
def
test_reverse_foreign_key_retrieve
(
self
):
queryset
=
ForeignKeyTarget
.
objects
.
all
()
serializer
=
ForeignKeyTargetSerializer
(
queryset
,
many
=
True
,
context
=
{
'request'
:
request
})
expected
=
[
{
'url'
:
'http://testserver/foreignkeytarget/1/'
,
'name'
:
'target-1'
,
'sources'
:
[
'http://testserver/foreignkeysource/1/'
,
'http://testserver/foreignkeysource/2/'
,
'http://testserver/foreignkeysource/3/'
]},
{
'url'
:
'http://testserver/foreignkeytarget/2/'
,
'name'
:
'target-2'
,
'sources'
:
[]},
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
def
test_foreign_key_update
(
self
):
data
=
{
'url'
:
'http://testserver/foreignkeysource/1/'
,
'name'
:
'source-1'
,
'target'
:
'http://testserver/foreignkeytarget/2/'
}
instance
=
ForeignKeySource
.
objects
.
get
(
pk
=
1
)
serializer
=
ForeignKeySourceSerializer
(
instance
,
data
=
data
,
context
=
{
'request'
:
request
})
self
.
assertTrue
(
serializer
.
is_valid
())
self
.
assertEqual
(
serializer
.
data
,
data
)
serializer
.
save
()
# Ensure source 1 is updated, and everything else is as expected
queryset
=
ForeignKeySource
.
objects
.
all
()
serializer
=
ForeignKeySourceSerializer
(
queryset
,
many
=
True
,
context
=
{
'request'
:
request
})
expected
=
[
{
'url'
:
'http://testserver/foreignkeysource/1/'
,
'name'
:
'source-1'
,
'target'
:
'http://testserver/foreignkeytarget/2/'
},
{
'url'
:
'http://testserver/foreignkeysource/2/'
,
'name'
:
'source-2'
,
'target'
:
'http://testserver/foreignkeytarget/1/'
},
{
'url'
:
'http://testserver/foreignkeysource/3/'
,
'name'
:
'source-3'
,
'target'
:
'http://testserver/foreignkeytarget/1/'
}
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
def
test_foreign_key_update_incorrect_type
(
self
):
data
=
{
'url'
:
'http://testserver/foreignkeysource/1/'
,
'name'
:
'source-1'
,
'target'
:
2
}
instance
=
ForeignKeySource
.
objects
.
get
(
pk
=
1
)
serializer
=
ForeignKeySourceSerializer
(
instance
,
data
=
data
,
context
=
{
'request'
:
request
})
self
.
assertFalse
(
serializer
.
is_valid
())
self
.
assertEqual
(
serializer
.
errors
,
{
'target'
:
[
'Incorrect type. Expected url string, received int.'
]})
def
test_reverse_foreign_key_update
(
self
):
data
=
{
'url'
:
'http://testserver/foreignkeytarget/2/'
,
'name'
:
'target-2'
,
'sources'
:
[
'http://testserver/foreignkeysource/1/'
,
'http://testserver/foreignkeysource/3/'
]}
instance
=
ForeignKeyTarget
.
objects
.
get
(
pk
=
2
)
serializer
=
ForeignKeyTargetSerializer
(
instance
,
data
=
data
,
context
=
{
'request'
:
request
})
self
.
assertTrue
(
serializer
.
is_valid
())
# We shouldn't have saved anything to the db yet since save
# hasn't been called.
queryset
=
ForeignKeyTarget
.
objects
.
all
()
new_serializer
=
ForeignKeyTargetSerializer
(
queryset
,
many
=
True
,
context
=
{
'request'
:
request
})
expected
=
[
{
'url'
:
'http://testserver/foreignkeytarget/1/'
,
'name'
:
'target-1'
,
'sources'
:
[
'http://testserver/foreignkeysource/1/'
,
'http://testserver/foreignkeysource/2/'
,
'http://testserver/foreignkeysource/3/'
]},
{
'url'
:
'http://testserver/foreignkeytarget/2/'
,
'name'
:
'target-2'
,
'sources'
:
[]},
]
self
.
assertEqual
(
new_serializer
.
data
,
expected
)
serializer
.
save
()
self
.
assertEqual
(
serializer
.
data
,
data
)
# Ensure target 2 is update, and everything else is as expected
queryset
=
ForeignKeyTarget
.
objects
.
all
()
serializer
=
ForeignKeyTargetSerializer
(
queryset
,
many
=
True
,
context
=
{
'request'
:
request
})
expected
=
[
{
'url'
:
'http://testserver/foreignkeytarget/1/'
,
'name'
:
'target-1'
,
'sources'
:
[
'http://testserver/foreignkeysource/2/'
]},
{
'url'
:
'http://testserver/foreignkeytarget/2/'
,
'name'
:
'target-2'
,
'sources'
:
[
'http://testserver/foreignkeysource/1/'
,
'http://testserver/foreignkeysource/3/'
]},
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
def
test_foreign_key_create
(
self
):
data
=
{
'url'
:
'http://testserver/foreignkeysource/4/'
,
'name'
:
'source-4'
,
'target'
:
'http://testserver/foreignkeytarget/2/'
}
serializer
=
ForeignKeySourceSerializer
(
data
=
data
,
context
=
{
'request'
:
request
})
self
.
assertTrue
(
serializer
.
is_valid
())
obj
=
serializer
.
save
()
self
.
assertEqual
(
serializer
.
data
,
data
)
self
.
assertEqual
(
obj
.
name
,
'source-4'
)
# Ensure source 1 is updated, and everything else is as expected
queryset
=
ForeignKeySource
.
objects
.
all
()
serializer
=
ForeignKeySourceSerializer
(
queryset
,
many
=
True
,
context
=
{
'request'
:
request
})
expected
=
[
{
'url'
:
'http://testserver/foreignkeysource/1/'
,
'name'
:
'source-1'
,
'target'
:
'http://testserver/foreignkeytarget/1/'
},
{
'url'
:
'http://testserver/foreignkeysource/2/'
,
'name'
:
'source-2'
,
'target'
:
'http://testserver/foreignkeytarget/1/'
},
{
'url'
:
'http://testserver/foreignkeysource/3/'
,
'name'
:
'source-3'
,
'target'
:
'http://testserver/foreignkeytarget/1/'
},
{
'url'
:
'http://testserver/foreignkeysource/4/'
,
'name'
:
'source-4'
,
'target'
:
'http://testserver/foreignkeytarget/2/'
},
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
def
test_reverse_foreign_key_create
(
self
):
data
=
{
'url'
:
'http://testserver/foreignkeytarget/3/'
,
'name'
:
'target-3'
,
'sources'
:
[
'http://testserver/foreignkeysource/1/'
,
'http://testserver/foreignkeysource/3/'
]}
serializer
=
ForeignKeyTargetSerializer
(
data
=
data
,
context
=
{
'request'
:
request
})
self
.
assertTrue
(
serializer
.
is_valid
())
obj
=
serializer
.
save
()
self
.
assertEqual
(
serializer
.
data
,
data
)
self
.
assertEqual
(
obj
.
name
,
'target-3'
)
# Ensure target 4 is added, and everything else is as expected
queryset
=
ForeignKeyTarget
.
objects
.
all
()
serializer
=
ForeignKeyTargetSerializer
(
queryset
,
many
=
True
,
context
=
{
'request'
:
request
})
expected
=
[
{
'url'
:
'http://testserver/foreignkeytarget/1/'
,
'name'
:
'target-1'
,
'sources'
:
[
'http://testserver/foreignkeysource/2/'
]},
{
'url'
:
'http://testserver/foreignkeytarget/2/'
,
'name'
:
'target-2'
,
'sources'
:
[]},
{
'url'
:
'http://testserver/foreignkeytarget/3/'
,
'name'
:
'target-3'
,
'sources'
:
[
'http://testserver/foreignkeysource/1/'
,
'http://testserver/foreignkeysource/3/'
]},
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
def
test_foreign_key_update_with_invalid_null
(
self
):
data
=
{
'url'
:
'http://testserver/foreignkeysource/1/'
,
'name'
:
'source-1'
,
'target'
:
None
}
instance
=
ForeignKeySource
.
objects
.
get
(
pk
=
1
)
serializer
=
ForeignKeySourceSerializer
(
instance
,
data
=
data
,
context
=
{
'request'
:
request
})
self
.
assertFalse
(
serializer
.
is_valid
())
self
.
assertEqual
(
serializer
.
errors
,
{
'target'
:
[
'This field is required.'
]})
class
HyperlinkedNullableForeignKeyTests
(
TestCase
):
urls
=
'tests.test_relations_hyperlink'
def
setUp
(
self
):
target
=
ForeignKeyTarget
(
name
=
'target-1'
)
target
.
save
()
for
idx
in
range
(
1
,
4
):
if
idx
==
3
:
target
=
None
source
=
NullableForeignKeySource
(
name
=
'source-
%
d'
%
idx
,
target
=
target
)
source
.
save
()
def
test_foreign_key_retrieve_with_null
(
self
):
queryset
=
NullableForeignKeySource
.
objects
.
all
()
serializer
=
NullableForeignKeySourceSerializer
(
queryset
,
many
=
True
,
context
=
{
'request'
:
request
})
expected
=
[
{
'url'
:
'http://testserver/nullableforeignkeysource/1/'
,
'name'
:
'source-1'
,
'target'
:
'http://testserver/foreignkeytarget/1/'
},
{
'url'
:
'http://testserver/nullableforeignkeysource/2/'
,
'name'
:
'source-2'
,
'target'
:
'http://testserver/foreignkeytarget/1/'
},
{
'url'
:
'http://testserver/nullableforeignkeysource/3/'
,
'name'
:
'source-3'
,
'target'
:
None
},
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
def
test_foreign_key_create_with_valid_null
(
self
):
data
=
{
'url'
:
'http://testserver/nullableforeignkeysource/4/'
,
'name'
:
'source-4'
,
'target'
:
None
}
serializer
=
NullableForeignKeySourceSerializer
(
data
=
data
,
context
=
{
'request'
:
request
})
self
.
assertTrue
(
serializer
.
is_valid
())
obj
=
serializer
.
save
()
self
.
assertEqual
(
serializer
.
data
,
data
)
self
.
assertEqual
(
obj
.
name
,
'source-4'
)
# Ensure source 4 is created, and everything else is as expected
queryset
=
NullableForeignKeySource
.
objects
.
all
()
serializer
=
NullableForeignKeySourceSerializer
(
queryset
,
many
=
True
,
context
=
{
'request'
:
request
})
expected
=
[
{
'url'
:
'http://testserver/nullableforeignkeysource/1/'
,
'name'
:
'source-1'
,
'target'
:
'http://testserver/foreignkeytarget/1/'
},
{
'url'
:
'http://testserver/nullableforeignkeysource/2/'
,
'name'
:
'source-2'
,
'target'
:
'http://testserver/foreignkeytarget/1/'
},
{
'url'
:
'http://testserver/nullableforeignkeysource/3/'
,
'name'
:
'source-3'
,
'target'
:
None
},
{
'url'
:
'http://testserver/nullableforeignkeysource/4/'
,
'name'
:
'source-4'
,
'target'
:
None
}
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
def
test_foreign_key_create_with_valid_emptystring
(
self
):
"""
The emptystring should be interpreted as null in the context
of relationships.
"""
data
=
{
'url'
:
'http://testserver/nullableforeignkeysource/4/'
,
'name'
:
'source-4'
,
'target'
:
''
}
expected_data
=
{
'url'
:
'http://testserver/nullableforeignkeysource/4/'
,
'name'
:
'source-4'
,
'target'
:
None
}
serializer
=
NullableForeignKeySourceSerializer
(
data
=
data
,
context
=
{
'request'
:
request
})
self
.
assertTrue
(
serializer
.
is_valid
())
obj
=
serializer
.
save
()
self
.
assertEqual
(
serializer
.
data
,
expected_data
)
self
.
assertEqual
(
obj
.
name
,
'source-4'
)
# Ensure source 4 is created, and everything else is as expected
queryset
=
NullableForeignKeySource
.
objects
.
all
()
serializer
=
NullableForeignKeySourceSerializer
(
queryset
,
many
=
True
,
context
=
{
'request'
:
request
})
expected
=
[
{
'url'
:
'http://testserver/nullableforeignkeysource/1/'
,
'name'
:
'source-1'
,
'target'
:
'http://testserver/foreignkeytarget/1/'
},
{
'url'
:
'http://testserver/nullableforeignkeysource/2/'
,
'name'
:
'source-2'
,
'target'
:
'http://testserver/foreignkeytarget/1/'
},
{
'url'
:
'http://testserver/nullableforeignkeysource/3/'
,
'name'
:
'source-3'
,
'target'
:
None
},
{
'url'
:
'http://testserver/nullableforeignkeysource/4/'
,
'name'
:
'source-4'
,
'target'
:
None
}
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
def
test_foreign_key_update_with_valid_null
(
self
):
data
=
{
'url'
:
'http://testserver/nullableforeignkeysource/1/'
,
'name'
:
'source-1'
,
'target'
:
None
}
instance
=
NullableForeignKeySource
.
objects
.
get
(
pk
=
1
)
serializer
=
NullableForeignKeySourceSerializer
(
instance
,
data
=
data
,
context
=
{
'request'
:
request
})
self
.
assertTrue
(
serializer
.
is_valid
())
self
.
assertEqual
(
serializer
.
data
,
data
)
serializer
.
save
()
# Ensure source 1 is updated, and everything else is as expected
queryset
=
NullableForeignKeySource
.
objects
.
all
()
serializer
=
NullableForeignKeySourceSerializer
(
queryset
,
many
=
True
,
context
=
{
'request'
:
request
})
expected
=
[
{
'url'
:
'http://testserver/nullableforeignkeysource/1/'
,
'name'
:
'source-1'
,
'target'
:
None
},
{
'url'
:
'http://testserver/nullableforeignkeysource/2/'
,
'name'
:
'source-2'
,
'target'
:
'http://testserver/foreignkeytarget/1/'
},
{
'url'
:
'http://testserver/nullableforeignkeysource/3/'
,
'name'
:
'source-3'
,
'target'
:
None
},
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
def
test_foreign_key_update_with_valid_emptystring
(
self
):
"""
The emptystring should be interpreted as null in the context
of relationships.
"""
data
=
{
'url'
:
'http://testserver/nullableforeignkeysource/1/'
,
'name'
:
'source-1'
,
'target'
:
''
}
expected_data
=
{
'url'
:
'http://testserver/nullableforeignkeysource/1/'
,
'name'
:
'source-1'
,
'target'
:
None
}
instance
=
NullableForeignKeySource
.
objects
.
get
(
pk
=
1
)
serializer
=
NullableForeignKeySourceSerializer
(
instance
,
data
=
data
,
context
=
{
'request'
:
request
})
self
.
assertTrue
(
serializer
.
is_valid
())
self
.
assertEqual
(
serializer
.
data
,
expected_data
)
serializer
.
save
()
# Ensure source 1 is updated, and everything else is as expected
queryset
=
NullableForeignKeySource
.
objects
.
all
()
serializer
=
NullableForeignKeySourceSerializer
(
queryset
,
many
=
True
,
context
=
{
'request'
:
request
})
expected
=
[
{
'url'
:
'http://testserver/nullableforeignkeysource/1/'
,
'name'
:
'source-1'
,
'target'
:
None
},
{
'url'
:
'http://testserver/nullableforeignkeysource/2/'
,
'name'
:
'source-2'
,
'target'
:
'http://testserver/foreignkeytarget/1/'
},
{
'url'
:
'http://testserver/nullableforeignkeysource/3/'
,
'name'
:
'source-3'
,
'target'
:
None
},
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
# reverse foreign keys MUST be read_only
# In the general case they do not provide .remove() or .clear()
# and cannot be arbitrarily set.
# def test_reverse_foreign_key_update(self):
# data = {'id': 1, 'name': 'target-1', 'sources': [1]}
# instance = ForeignKeyTarget.objects.get(pk=1)
# serializer = ForeignKeyTargetSerializer(instance, data=data)
# self.assertTrue(serializer.is_valid())
# self.assertEqual(serializer.data, data)
# serializer.save()
# # Ensure target 1 is updated, and everything else is as expected
# queryset = ForeignKeyTarget.objects.all()
# serializer = ForeignKeyTargetSerializer(queryset, many=True)
# expected = [
# {'id': 1, 'name': 'target-1', 'sources': [1]},
# {'id': 2, 'name': 'target-2', 'sources': []},
# ]
# self.assertEqual(serializer.data, expected)
class
HyperlinkedNullableOneToOneTests
(
TestCase
):
urls
=
'tests.test_relations_hyperlink'
def
setUp
(
self
):
target
=
OneToOneTarget
(
name
=
'target-1'
)
target
.
save
()
new_target
=
OneToOneTarget
(
name
=
'target-2'
)
new_target
.
save
()
source
=
NullableOneToOneSource
(
name
=
'source-1'
,
target
=
target
)
source
.
save
()
def
test_reverse_foreign_key_retrieve_with_null
(
self
):
queryset
=
OneToOneTarget
.
objects
.
all
()
serializer
=
NullableOneToOneTargetSerializer
(
queryset
,
many
=
True
,
context
=
{
'request'
:
request
})
expected
=
[
{
'url'
:
'http://testserver/onetoonetarget/1/'
,
'name'
:
'target-1'
,
'nullable_source'
:
'http://testserver/nullableonetoonesource/1/'
},
{
'url'
:
'http://testserver/onetoonetarget/2/'
,
'name'
:
'target-2'
,
'nullable_source'
:
None
},
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
# Regression tests for #694 (`source` attribute on related fields)
class
HyperlinkedRelatedFieldSourceTests
(
TestCase
):
urls
=
'tests.test_relations_hyperlink'
def
test_related_manager_source
(
self
):
"""
Relational fields should be able to use manager-returning methods as their source.
"""
BlogPost
.
objects
.
create
(
title
=
'blah'
)
field
=
serializers
.
HyperlinkedRelatedField
(
many
=
True
,
source
=
'get_blogposts_manager'
,
view_name
=
'dummy-url'
,
)
field
.
context
=
{
'request'
:
request
}
class
ClassWithManagerMethod
(
object
):
def
get_blogposts_manager
(
self
):
return
BlogPost
.
objects
obj
=
ClassWithManagerMethod
()
value
=
field
.
field_to_native
(
obj
,
'field_name'
)
self
.
assertEqual
(
value
,
[
'http://testserver/dummyurl/1/'
])
def
test_related_queryset_source
(
self
):
"""
Relational fields should be able to use queryset-returning methods as their source.
"""
BlogPost
.
objects
.
create
(
title
=
'blah'
)
field
=
serializers
.
HyperlinkedRelatedField
(
many
=
True
,
source
=
'get_blogposts_queryset'
,
view_name
=
'dummy-url'
,
)
field
.
context
=
{
'request'
:
request
}
class
ClassWithQuerysetMethod
(
object
):
def
get_blogposts_queryset
(
self
):
return
BlogPost
.
objects
.
all
()
obj
=
ClassWithQuerysetMethod
()
value
=
field
.
field_to_native
(
obj
,
'field_name'
)
self
.
assertEqual
(
value
,
[
'http://testserver/dummyurl/1/'
])
def
test_dotted_source
(
self
):
"""
Source argument should support dotted.source notation.
"""
BlogPost
.
objects
.
create
(
title
=
'blah'
)
field
=
serializers
.
HyperlinkedRelatedField
(
many
=
True
,
source
=
'a.b.c'
,
view_name
=
'dummy-url'
,
)
field
.
context
=
{
'request'
:
request
}
class
ClassWithQuerysetMethod
(
object
):
a
=
{
'b'
:
{
'c'
:
BlogPost
.
objects
.
all
()
}
}
obj
=
ClassWithQuerysetMethod
()
value
=
field
.
field_to_native
(
obj
,
'field_name'
)
self
.
assertEqual
(
value
,
[
'http://testserver/dummyurl/1/'
])
#
from __future__ import unicode_literals
#
from django.conf.urls import patterns, url
#
from django.test import TestCase
#
from rest_framework import serializers
#
from rest_framework.test import APIRequestFactory
#
from tests.models import (
#
BlogPost,
#
ManyToManyTarget, ManyToManySource, ForeignKeyTarget, ForeignKeySource,
#
NullableForeignKeySource, OneToOneTarget, NullableOneToOneSource
#
)
#
factory = APIRequestFactory()
#
request = factory.get('/') # Just to ensure we have a request in the serializer context
#
def dummy_view(request, pk):
#
pass
#
urlpatterns = patterns(
#
'',
#
url(r'^dummyurl/(?P<pk>[0-9]+)/$', dummy_view, name='dummy-url'),
#
url(r'^manytomanysource/(?P<pk>[0-9]+)/$', dummy_view, name='manytomanysource-detail'),
#
url(r'^manytomanytarget/(?P<pk>[0-9]+)/$', dummy_view, name='manytomanytarget-detail'),
#
url(r'^foreignkeysource/(?P<pk>[0-9]+)/$', dummy_view, name='foreignkeysource-detail'),
#
url(r'^foreignkeytarget/(?P<pk>[0-9]+)/$', dummy_view, name='foreignkeytarget-detail'),
#
url(r'^nullableforeignkeysource/(?P<pk>[0-9]+)/$', dummy_view, name='nullableforeignkeysource-detail'),
#
url(r'^onetoonetarget/(?P<pk>[0-9]+)/$', dummy_view, name='onetoonetarget-detail'),
#
url(r'^nullableonetoonesource/(?P<pk>[0-9]+)/$', dummy_view, name='nullableonetoonesource-detail'),
#
)
#
#
ManyToMany
#
class ManyToManyTargetSerializer(serializers.HyperlinkedModelSerializer):
#
class Meta:
#
model = ManyToManyTarget
#
fields = ('url', 'name', 'sources')
#
class ManyToManySourceSerializer(serializers.HyperlinkedModelSerializer):
#
class Meta:
#
model = ManyToManySource
#
fields = ('url', 'name', 'targets')
#
#
ForeignKey
#
class ForeignKeyTargetSerializer(serializers.HyperlinkedModelSerializer):
#
class Meta:
#
model = ForeignKeyTarget
#
fields = ('url', 'name', 'sources')
#
class ForeignKeySourceSerializer(serializers.HyperlinkedModelSerializer):
#
class Meta:
#
model = ForeignKeySource
#
fields = ('url', 'name', 'target')
#
#
Nullable ForeignKey
#
class NullableForeignKeySourceSerializer(serializers.HyperlinkedModelSerializer):
#
class Meta:
#
model = NullableForeignKeySource
#
fields = ('url', 'name', 'target')
#
#
Nullable OneToOne
#
class NullableOneToOneTargetSerializer(serializers.HyperlinkedModelSerializer):
#
class Meta:
#
model = OneToOneTarget
#
fields = ('url', 'name', 'nullable_source')
#
#
TODO: Add test that .data cannot be accessed prior to .is_valid
#
class HyperlinkedManyToManyTests(TestCase):
#
urls = 'tests.test_relations_hyperlink'
#
def setUp(self):
#
for idx in range(1, 4):
#
target = ManyToManyTarget(name='target-%d' % idx)
#
target.save()
#
source = ManyToManySource(name='source-%d' % idx)
#
source.save()
#
for target in ManyToManyTarget.objects.all():
#
source.targets.add(target)
#
def test_many_to_many_retrieve(self):
#
queryset = ManyToManySource.objects.all()
#
serializer = ManyToManySourceSerializer(queryset, many=True, context={'request': request})
#
expected = [
#
{'url': 'http://testserver/manytomanysource/1/', 'name': 'source-1', 'targets': ['http://testserver/manytomanytarget/1/']},
#
{'url': 'http://testserver/manytomanysource/2/', 'name': 'source-2', 'targets': ['http://testserver/manytomanytarget/1/', 'http://testserver/manytomanytarget/2/']},
#
{'url': 'http://testserver/manytomanysource/3/', 'name': 'source-3', 'targets': ['http://testserver/manytomanytarget/1/', 'http://testserver/manytomanytarget/2/', 'http://testserver/manytomanytarget/3/']}
#
]
#
self.assertEqual(serializer.data, expected)
#
def test_reverse_many_to_many_retrieve(self):
#
queryset = ManyToManyTarget.objects.all()
#
serializer = ManyToManyTargetSerializer(queryset, many=True, context={'request': request})
#
expected = [
#
{'url': 'http://testserver/manytomanytarget/1/', 'name': 'target-1', 'sources': ['http://testserver/manytomanysource/1/', 'http://testserver/manytomanysource/2/', 'http://testserver/manytomanysource/3/']},
#
{'url': 'http://testserver/manytomanytarget/2/', 'name': 'target-2', 'sources': ['http://testserver/manytomanysource/2/', 'http://testserver/manytomanysource/3/']},
#
{'url': 'http://testserver/manytomanytarget/3/', 'name': 'target-3', 'sources': ['http://testserver/manytomanysource/3/']}
#
]
#
self.assertEqual(serializer.data, expected)
#
def test_many_to_many_update(self):
#
data = {'url': 'http://testserver/manytomanysource/1/', 'name': 'source-1', 'targets': ['http://testserver/manytomanytarget/1/', 'http://testserver/manytomanytarget/2/', 'http://testserver/manytomanytarget/3/']}
#
instance = ManyToManySource.objects.get(pk=1)
#
serializer = ManyToManySourceSerializer(instance, data=data, context={'request': request})
#
self.assertTrue(serializer.is_valid())
#
serializer.save()
#
self.assertEqual(serializer.data, data)
#
# Ensure source 1 is updated, and everything else is as expected
#
queryset = ManyToManySource.objects.all()
#
serializer = ManyToManySourceSerializer(queryset, many=True, context={'request': request})
#
expected = [
#
{'url': 'http://testserver/manytomanysource/1/', 'name': 'source-1', 'targets': ['http://testserver/manytomanytarget/1/', 'http://testserver/manytomanytarget/2/', 'http://testserver/manytomanytarget/3/']},
#
{'url': 'http://testserver/manytomanysource/2/', 'name': 'source-2', 'targets': ['http://testserver/manytomanytarget/1/', 'http://testserver/manytomanytarget/2/']},
#
{'url': 'http://testserver/manytomanysource/3/', 'name': 'source-3', 'targets': ['http://testserver/manytomanytarget/1/', 'http://testserver/manytomanytarget/2/', 'http://testserver/manytomanytarget/3/']}
#
]
#
self.assertEqual(serializer.data, expected)
#
def test_reverse_many_to_many_update(self):
#
data = {'url': 'http://testserver/manytomanytarget/1/', 'name': 'target-1', 'sources': ['http://testserver/manytomanysource/1/']}
#
instance = ManyToManyTarget.objects.get(pk=1)
#
serializer = ManyToManyTargetSerializer(instance, data=data, context={'request': request})
#
self.assertTrue(serializer.is_valid())
#
serializer.save()
#
self.assertEqual(serializer.data, data)
#
# Ensure target 1 is updated, and everything else is as expected
#
queryset = ManyToManyTarget.objects.all()
#
serializer = ManyToManyTargetSerializer(queryset, many=True, context={'request': request})
#
expected = [
#
{'url': 'http://testserver/manytomanytarget/1/', 'name': 'target-1', 'sources': ['http://testserver/manytomanysource/1/']},
#
{'url': 'http://testserver/manytomanytarget/2/', 'name': 'target-2', 'sources': ['http://testserver/manytomanysource/2/', 'http://testserver/manytomanysource/3/']},
#
{'url': 'http://testserver/manytomanytarget/3/', 'name': 'target-3', 'sources': ['http://testserver/manytomanysource/3/']}
#
]
#
self.assertEqual(serializer.data, expected)
#
def test_many_to_many_create(self):
#
data = {'url': 'http://testserver/manytomanysource/4/', 'name': 'source-4', 'targets': ['http://testserver/manytomanytarget/1/', 'http://testserver/manytomanytarget/3/']}
#
serializer = ManyToManySourceSerializer(data=data, context={'request': request})
#
self.assertTrue(serializer.is_valid())
#
obj = serializer.save()
#
self.assertEqual(serializer.data, data)
#
self.assertEqual(obj.name, 'source-4')
#
# Ensure source 4 is added, and everything else is as expected
#
queryset = ManyToManySource.objects.all()
#
serializer = ManyToManySourceSerializer(queryset, many=True, context={'request': request})
#
expected = [
#
{'url': 'http://testserver/manytomanysource/1/', 'name': 'source-1', 'targets': ['http://testserver/manytomanytarget/1/']},
#
{'url': 'http://testserver/manytomanysource/2/', 'name': 'source-2', 'targets': ['http://testserver/manytomanytarget/1/', 'http://testserver/manytomanytarget/2/']},
#
{'url': 'http://testserver/manytomanysource/3/', 'name': 'source-3', 'targets': ['http://testserver/manytomanytarget/1/', 'http://testserver/manytomanytarget/2/', 'http://testserver/manytomanytarget/3/']},
#
{'url': 'http://testserver/manytomanysource/4/', 'name': 'source-4', 'targets': ['http://testserver/manytomanytarget/1/', 'http://testserver/manytomanytarget/3/']}
#
]
#
self.assertEqual(serializer.data, expected)
#
def test_reverse_many_to_many_create(self):
#
data = {'url': 'http://testserver/manytomanytarget/4/', 'name': 'target-4', 'sources': ['http://testserver/manytomanysource/1/', 'http://testserver/manytomanysource/3/']}
#
serializer = ManyToManyTargetSerializer(data=data, context={'request': request})
#
self.assertTrue(serializer.is_valid())
#
obj = serializer.save()
#
self.assertEqual(serializer.data, data)
#
self.assertEqual(obj.name, 'target-4')
#
# Ensure target 4 is added, and everything else is as expected
#
queryset = ManyToManyTarget.objects.all()
#
serializer = ManyToManyTargetSerializer(queryset, many=True, context={'request': request})
#
expected = [
#
{'url': 'http://testserver/manytomanytarget/1/', 'name': 'target-1', 'sources': ['http://testserver/manytomanysource/1/', 'http://testserver/manytomanysource/2/', 'http://testserver/manytomanysource/3/']},
#
{'url': 'http://testserver/manytomanytarget/2/', 'name': 'target-2', 'sources': ['http://testserver/manytomanysource/2/', 'http://testserver/manytomanysource/3/']},
#
{'url': 'http://testserver/manytomanytarget/3/', 'name': 'target-3', 'sources': ['http://testserver/manytomanysource/3/']},
#
{'url': 'http://testserver/manytomanytarget/4/', 'name': 'target-4', 'sources': ['http://testserver/manytomanysource/1/', 'http://testserver/manytomanysource/3/']}
#
]
#
self.assertEqual(serializer.data, expected)
#
class HyperlinkedForeignKeyTests(TestCase):
#
urls = 'tests.test_relations_hyperlink'
#
def setUp(self):
#
target = ForeignKeyTarget(name='target-1')
#
target.save()
#
new_target = ForeignKeyTarget(name='target-2')
#
new_target.save()
#
for idx in range(1, 4):
#
source = ForeignKeySource(name='source-%d' % idx, target=target)
#
source.save()
#
def test_foreign_key_retrieve(self):
#
queryset = ForeignKeySource.objects.all()
#
serializer = ForeignKeySourceSerializer(queryset, many=True, context={'request': request})
#
expected = [
#
{'url': 'http://testserver/foreignkeysource/1/', 'name': 'source-1', 'target': 'http://testserver/foreignkeytarget/1/'},
#
{'url': 'http://testserver/foreignkeysource/2/', 'name': 'source-2', 'target': 'http://testserver/foreignkeytarget/1/'},
#
{'url': 'http://testserver/foreignkeysource/3/', 'name': 'source-3', 'target': 'http://testserver/foreignkeytarget/1/'}
#
]
#
self.assertEqual(serializer.data, expected)
#
def test_reverse_foreign_key_retrieve(self):
#
queryset = ForeignKeyTarget.objects.all()
#
serializer = ForeignKeyTargetSerializer(queryset, many=True, context={'request': request})
#
expected = [
#
{'url': 'http://testserver/foreignkeytarget/1/', 'name': 'target-1', 'sources': ['http://testserver/foreignkeysource/1/', 'http://testserver/foreignkeysource/2/', 'http://testserver/foreignkeysource/3/']},
#
{'url': 'http://testserver/foreignkeytarget/2/', 'name': 'target-2', 'sources': []},
#
]
#
self.assertEqual(serializer.data, expected)
#
def test_foreign_key_update(self):
#
data = {'url': 'http://testserver/foreignkeysource/1/', 'name': 'source-1', 'target': 'http://testserver/foreignkeytarget/2/'}
#
instance = ForeignKeySource.objects.get(pk=1)
#
serializer = ForeignKeySourceSerializer(instance, data=data, context={'request': request})
#
self.assertTrue(serializer.is_valid())
#
self.assertEqual(serializer.data, data)
#
serializer.save()
#
# Ensure source 1 is updated, and everything else is as expected
#
queryset = ForeignKeySource.objects.all()
#
serializer = ForeignKeySourceSerializer(queryset, many=True, context={'request': request})
#
expected = [
#
{'url': 'http://testserver/foreignkeysource/1/', 'name': 'source-1', 'target': 'http://testserver/foreignkeytarget/2/'},
#
{'url': 'http://testserver/foreignkeysource/2/', 'name': 'source-2', 'target': 'http://testserver/foreignkeytarget/1/'},
#
{'url': 'http://testserver/foreignkeysource/3/', 'name': 'source-3', 'target': 'http://testserver/foreignkeytarget/1/'}
#
]
#
self.assertEqual(serializer.data, expected)
#
def test_foreign_key_update_incorrect_type(self):
#
data = {'url': 'http://testserver/foreignkeysource/1/', 'name': 'source-1', 'target': 2}
#
instance = ForeignKeySource.objects.get(pk=1)
#
serializer = ForeignKeySourceSerializer(instance, data=data, context={'request': request})
#
self.assertFalse(serializer.is_valid())
#
self.assertEqual(serializer.errors, {'target': ['Incorrect type. Expected url string, received int.']})
#
def test_reverse_foreign_key_update(self):
#
data = {'url': 'http://testserver/foreignkeytarget/2/', 'name': 'target-2', 'sources': ['http://testserver/foreignkeysource/1/', 'http://testserver/foreignkeysource/3/']}
#
instance = ForeignKeyTarget.objects.get(pk=2)
#
serializer = ForeignKeyTargetSerializer(instance, data=data, context={'request': request})
#
self.assertTrue(serializer.is_valid())
#
# We shouldn't have saved anything to the db yet since save
#
# hasn't been called.
#
queryset = ForeignKeyTarget.objects.all()
#
new_serializer = ForeignKeyTargetSerializer(queryset, many=True, context={'request': request})
#
expected = [
#
{'url': 'http://testserver/foreignkeytarget/1/', 'name': 'target-1', 'sources': ['http://testserver/foreignkeysource/1/', 'http://testserver/foreignkeysource/2/', 'http://testserver/foreignkeysource/3/']},
#
{'url': 'http://testserver/foreignkeytarget/2/', 'name': 'target-2', 'sources': []},
#
]
#
self.assertEqual(new_serializer.data, expected)
#
serializer.save()
#
self.assertEqual(serializer.data, data)
#
# Ensure target 2 is update, and everything else is as expected
#
queryset = ForeignKeyTarget.objects.all()
#
serializer = ForeignKeyTargetSerializer(queryset, many=True, context={'request': request})
#
expected = [
#
{'url': 'http://testserver/foreignkeytarget/1/', 'name': 'target-1', 'sources': ['http://testserver/foreignkeysource/2/']},
#
{'url': 'http://testserver/foreignkeytarget/2/', 'name': 'target-2', 'sources': ['http://testserver/foreignkeysource/1/', 'http://testserver/foreignkeysource/3/']},
#
]
#
self.assertEqual(serializer.data, expected)
#
def test_foreign_key_create(self):
#
data = {'url': 'http://testserver/foreignkeysource/4/', 'name': 'source-4', 'target': 'http://testserver/foreignkeytarget/2/'}
#
serializer = ForeignKeySourceSerializer(data=data, context={'request': request})
#
self.assertTrue(serializer.is_valid())
#
obj = serializer.save()
#
self.assertEqual(serializer.data, data)
#
self.assertEqual(obj.name, 'source-4')
#
# Ensure source 1 is updated, and everything else is as expected
#
queryset = ForeignKeySource.objects.all()
#
serializer = ForeignKeySourceSerializer(queryset, many=True, context={'request': request})
#
expected = [
#
{'url': 'http://testserver/foreignkeysource/1/', 'name': 'source-1', 'target': 'http://testserver/foreignkeytarget/1/'},
#
{'url': 'http://testserver/foreignkeysource/2/', 'name': 'source-2', 'target': 'http://testserver/foreignkeytarget/1/'},
#
{'url': 'http://testserver/foreignkeysource/3/', 'name': 'source-3', 'target': 'http://testserver/foreignkeytarget/1/'},
#
{'url': 'http://testserver/foreignkeysource/4/', 'name': 'source-4', 'target': 'http://testserver/foreignkeytarget/2/'},
#
]
#
self.assertEqual(serializer.data, expected)
#
def test_reverse_foreign_key_create(self):
#
data = {'url': 'http://testserver/foreignkeytarget/3/', 'name': 'target-3', 'sources': ['http://testserver/foreignkeysource/1/', 'http://testserver/foreignkeysource/3/']}
#
serializer = ForeignKeyTargetSerializer(data=data, context={'request': request})
#
self.assertTrue(serializer.is_valid())
#
obj = serializer.save()
#
self.assertEqual(serializer.data, data)
#
self.assertEqual(obj.name, 'target-3')
#
# Ensure target 4 is added, and everything else is as expected
#
queryset = ForeignKeyTarget.objects.all()
#
serializer = ForeignKeyTargetSerializer(queryset, many=True, context={'request': request})
#
expected = [
#
{'url': 'http://testserver/foreignkeytarget/1/', 'name': 'target-1', 'sources': ['http://testserver/foreignkeysource/2/']},
#
{'url': 'http://testserver/foreignkeytarget/2/', 'name': 'target-2', 'sources': []},
#
{'url': 'http://testserver/foreignkeytarget/3/', 'name': 'target-3', 'sources': ['http://testserver/foreignkeysource/1/', 'http://testserver/foreignkeysource/3/']},
#
]
#
self.assertEqual(serializer.data, expected)
#
def test_foreign_key_update_with_invalid_null(self):
#
data = {'url': 'http://testserver/foreignkeysource/1/', 'name': 'source-1', 'target': None}
#
instance = ForeignKeySource.objects.get(pk=1)
#
serializer = ForeignKeySourceSerializer(instance, data=data, context={'request': request})
#
self.assertFalse(serializer.is_valid())
#
self.assertEqual(serializer.errors, {'target': ['This field is required.']})
#
class HyperlinkedNullableForeignKeyTests(TestCase):
#
urls = 'tests.test_relations_hyperlink'
#
def setUp(self):
#
target = ForeignKeyTarget(name='target-1')
#
target.save()
#
for idx in range(1, 4):
#
if idx == 3:
#
target = None
#
source = NullableForeignKeySource(name='source-%d' % idx, target=target)
#
source.save()
#
def test_foreign_key_retrieve_with_null(self):
#
queryset = NullableForeignKeySource.objects.all()
#
serializer = NullableForeignKeySourceSerializer(queryset, many=True, context={'request': request})
#
expected = [
#
{'url': 'http://testserver/nullableforeignkeysource/1/', 'name': 'source-1', 'target': 'http://testserver/foreignkeytarget/1/'},
#
{'url': 'http://testserver/nullableforeignkeysource/2/', 'name': 'source-2', 'target': 'http://testserver/foreignkeytarget/1/'},
#
{'url': 'http://testserver/nullableforeignkeysource/3/', 'name': 'source-3', 'target': None},
#
]
#
self.assertEqual(serializer.data, expected)
#
def test_foreign_key_create_with_valid_null(self):
#
data = {'url': 'http://testserver/nullableforeignkeysource/4/', 'name': 'source-4', 'target': None}
#
serializer = NullableForeignKeySourceSerializer(data=data, context={'request': request})
#
self.assertTrue(serializer.is_valid())
#
obj = serializer.save()
#
self.assertEqual(serializer.data, data)
#
self.assertEqual(obj.name, 'source-4')
#
# Ensure source 4 is created, and everything else is as expected
#
queryset = NullableForeignKeySource.objects.all()
#
serializer = NullableForeignKeySourceSerializer(queryset, many=True, context={'request': request})
#
expected = [
#
{'url': 'http://testserver/nullableforeignkeysource/1/', 'name': 'source-1', 'target': 'http://testserver/foreignkeytarget/1/'},
#
{'url': 'http://testserver/nullableforeignkeysource/2/', 'name': 'source-2', 'target': 'http://testserver/foreignkeytarget/1/'},
#
{'url': 'http://testserver/nullableforeignkeysource/3/', 'name': 'source-3', 'target': None},
#
{'url': 'http://testserver/nullableforeignkeysource/4/', 'name': 'source-4', 'target': None}
#
]
#
self.assertEqual(serializer.data, expected)
#
def test_foreign_key_create_with_valid_emptystring(self):
#
"""
#
The emptystring should be interpreted as null in the context
#
of relationships.
#
"""
#
data = {'url': 'http://testserver/nullableforeignkeysource/4/', 'name': 'source-4', 'target': ''}
#
expected_data = {'url': 'http://testserver/nullableforeignkeysource/4/', 'name': 'source-4', 'target': None}
#
serializer = NullableForeignKeySourceSerializer(data=data, context={'request': request})
#
self.assertTrue(serializer.is_valid())
#
obj = serializer.save()
#
self.assertEqual(serializer.data, expected_data)
#
self.assertEqual(obj.name, 'source-4')
#
# Ensure source 4 is created, and everything else is as expected
#
queryset = NullableForeignKeySource.objects.all()
#
serializer = NullableForeignKeySourceSerializer(queryset, many=True, context={'request': request})
#
expected = [
#
{'url': 'http://testserver/nullableforeignkeysource/1/', 'name': 'source-1', 'target': 'http://testserver/foreignkeytarget/1/'},
#
{'url': 'http://testserver/nullableforeignkeysource/2/', 'name': 'source-2', 'target': 'http://testserver/foreignkeytarget/1/'},
#
{'url': 'http://testserver/nullableforeignkeysource/3/', 'name': 'source-3', 'target': None},
#
{'url': 'http://testserver/nullableforeignkeysource/4/', 'name': 'source-4', 'target': None}
#
]
#
self.assertEqual(serializer.data, expected)
#
def test_foreign_key_update_with_valid_null(self):
#
data = {'url': 'http://testserver/nullableforeignkeysource/1/', 'name': 'source-1', 'target': None}
#
instance = NullableForeignKeySource.objects.get(pk=1)
#
serializer = NullableForeignKeySourceSerializer(instance, data=data, context={'request': request})
#
self.assertTrue(serializer.is_valid())
#
self.assertEqual(serializer.data, data)
#
serializer.save()
#
# Ensure source 1 is updated, and everything else is as expected
#
queryset = NullableForeignKeySource.objects.all()
#
serializer = NullableForeignKeySourceSerializer(queryset, many=True, context={'request': request})
#
expected = [
#
{'url': 'http://testserver/nullableforeignkeysource/1/', 'name': 'source-1', 'target': None},
#
{'url': 'http://testserver/nullableforeignkeysource/2/', 'name': 'source-2', 'target': 'http://testserver/foreignkeytarget/1/'},
#
{'url': 'http://testserver/nullableforeignkeysource/3/', 'name': 'source-3', 'target': None},
#
]
#
self.assertEqual(serializer.data, expected)
#
def test_foreign_key_update_with_valid_emptystring(self):
#
"""
#
The emptystring should be interpreted as null in the context
#
of relationships.
#
"""
#
data = {'url': 'http://testserver/nullableforeignkeysource/1/', 'name': 'source-1', 'target': ''}
#
expected_data = {'url': 'http://testserver/nullableforeignkeysource/1/', 'name': 'source-1', 'target': None}
#
instance = NullableForeignKeySource.objects.get(pk=1)
#
serializer = NullableForeignKeySourceSerializer(instance, data=data, context={'request': request})
#
self.assertTrue(serializer.is_valid())
#
self.assertEqual(serializer.data, expected_data)
#
serializer.save()
#
# Ensure source 1 is updated, and everything else is as expected
#
queryset = NullableForeignKeySource.objects.all()
#
serializer = NullableForeignKeySourceSerializer(queryset, many=True, context={'request': request})
#
expected = [
#
{'url': 'http://testserver/nullableforeignkeysource/1/', 'name': 'source-1', 'target': None},
#
{'url': 'http://testserver/nullableforeignkeysource/2/', 'name': 'source-2', 'target': 'http://testserver/foreignkeytarget/1/'},
#
{'url': 'http://testserver/nullableforeignkeysource/3/', 'name': 'source-3', 'target': None},
#
]
#
self.assertEqual(serializer.data, expected)
#
# reverse foreign keys MUST be read_only
#
# In the general case they do not provide .remove() or .clear()
#
# and cannot be arbitrarily set.
#
# def test_reverse_foreign_key_update(self):
#
# data = {'id': 1, 'name': 'target-1', 'sources': [1]}
#
# instance = ForeignKeyTarget.objects.get(pk=1)
#
# serializer = ForeignKeyTargetSerializer(instance, data=data)
#
# self.assertTrue(serializer.is_valid())
#
# self.assertEqual(serializer.data, data)
#
# serializer.save()
#
# # Ensure target 1 is updated, and everything else is as expected
#
# queryset = ForeignKeyTarget.objects.all()
#
# serializer = ForeignKeyTargetSerializer(queryset, many=True)
#
# expected = [
#
# {'id': 1, 'name': 'target-1', 'sources': [1]},
#
# {'id': 2, 'name': 'target-2', 'sources': []},
#
# ]
#
# self.assertEqual(serializer.data, expected)
#
class HyperlinkedNullableOneToOneTests(TestCase):
#
urls = 'tests.test_relations_hyperlink'
#
def setUp(self):
#
target = OneToOneTarget(name='target-1')
#
target.save()
#
new_target = OneToOneTarget(name='target-2')
#
new_target.save()
#
source = NullableOneToOneSource(name='source-1', target=target)
#
source.save()
#
def test_reverse_foreign_key_retrieve_with_null(self):
#
queryset = OneToOneTarget.objects.all()
#
serializer = NullableOneToOneTargetSerializer(queryset, many=True, context={'request': request})
#
expected = [
#
{'url': 'http://testserver/onetoonetarget/1/', 'name': 'target-1', 'nullable_source': 'http://testserver/nullableonetoonesource/1/'},
#
{'url': 'http://testserver/onetoonetarget/2/', 'name': 'target-2', 'nullable_source': None},
#
]
#
self.assertEqual(serializer.data, expected)
#
#
Regression tests for #694 (`source` attribute on related fields)
#
class HyperlinkedRelatedFieldSourceTests(TestCase):
#
urls = 'tests.test_relations_hyperlink'
#
def test_related_manager_source(self):
#
"""
#
Relational fields should be able to use manager-returning methods as their source.
#
"""
#
BlogPost.objects.create(title='blah')
#
field = serializers.HyperlinkedRelatedField(
#
many=True,
#
source='get_blogposts_manager',
#
view_name='dummy-url',
#
)
#
field.context = {'request': request}
#
class ClassWithManagerMethod(object):
#
def get_blogposts_manager(self):
#
return BlogPost.objects
#
obj = ClassWithManagerMethod()
#
value = field.field_to_native(obj, 'field_name')
#
self.assertEqual(value, ['http://testserver/dummyurl/1/'])
#
def test_related_queryset_source(self):
#
"""
#
Relational fields should be able to use queryset-returning methods as their source.
#
"""
#
BlogPost.objects.create(title='blah')
#
field = serializers.HyperlinkedRelatedField(
#
many=True,
#
source='get_blogposts_queryset',
#
view_name='dummy-url',
#
)
#
field.context = {'request': request}
#
class ClassWithQuerysetMethod(object):
#
def get_blogposts_queryset(self):
#
return BlogPost.objects.all()
#
obj = ClassWithQuerysetMethod()
#
value = field.field_to_native(obj, 'field_name')
#
self.assertEqual(value, ['http://testserver/dummyurl/1/'])
#
def test_dotted_source(self):
#
"""
#
Source argument should support dotted.source notation.
#
"""
#
BlogPost.objects.create(title='blah')
#
field = serializers.HyperlinkedRelatedField(
#
many=True,
#
source='a.b.c',
#
view_name='dummy-url',
#
)
#
field.context = {'request': request}
#
class ClassWithQuerysetMethod(object):
#
a = {
#
'b': {
#
'c': BlogPost.objects.all()
#
}
#
}
#
obj = ClassWithQuerysetMethod()
#
value = field.field_to_native(obj, 'field_name')
#
self.assertEqual(value, ['http://testserver/dummyurl/1/'])
tests/test_relations_nested.py
View file @
f2852811
from
__future__
import
unicode_literals
from
django.db
import
models
from
django.test
import
TestCase
from
rest_framework
import
serializers
from
.models
import
OneToOneTarget
class
OneToOneSource
(
models
.
Model
):
name
=
models
.
CharField
(
max_length
=
100
)
target
=
models
.
OneToOneField
(
OneToOneTarget
,
related_name
=
'source'
,
null
=
True
,
blank
=
True
)
class
OneToManyTarget
(
models
.
Model
):
name
=
models
.
CharField
(
max_length
=
100
)
class
OneToManySource
(
models
.
Model
):
name
=
models
.
CharField
(
max_length
=
100
)
target
=
models
.
ForeignKey
(
OneToManyTarget
,
related_name
=
'sources'
)
class
ReverseNestedOneToOneTests
(
TestCase
):
def
setUp
(
self
):
class
OneToOneSourceSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
OneToOneSource
fields
=
(
'id'
,
'name'
)
class
OneToOneTargetSerializer
(
serializers
.
ModelSerializer
):
source
=
OneToOneSourceSerializer
()
class
Meta
:
model
=
OneToOneTarget
fields
=
(
'id'
,
'name'
,
'source'
)
self
.
Serializer
=
OneToOneTargetSerializer
for
idx
in
range
(
1
,
4
):
target
=
OneToOneTarget
(
name
=
'target-
%
d'
%
idx
)
target
.
save
()
source
=
OneToOneSource
(
name
=
'source-
%
d'
%
idx
,
target
=
target
)
source
.
save
()
def
test_one_to_one_retrieve
(
self
):
queryset
=
OneToOneTarget
.
objects
.
all
()
serializer
=
self
.
Serializer
(
queryset
,
many
=
True
)
expected
=
[
{
'id'
:
1
,
'name'
:
'target-1'
,
'source'
:
{
'id'
:
1
,
'name'
:
'source-1'
}},
{
'id'
:
2
,
'name'
:
'target-2'
,
'source'
:
{
'id'
:
2
,
'name'
:
'source-2'
}},
{
'id'
:
3
,
'name'
:
'target-3'
,
'source'
:
{
'id'
:
3
,
'name'
:
'source-3'
}}
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
def
test_one_to_one_create
(
self
):
data
=
{
'id'
:
4
,
'name'
:
'target-4'
,
'source'
:
{
'id'
:
4
,
'name'
:
'source-4'
}}
serializer
=
self
.
Serializer
(
data
=
data
)
self
.
assertTrue
(
serializer
.
is_valid
())
obj
=
serializer
.
save
()
self
.
assertEqual
(
serializer
.
data
,
data
)
self
.
assertEqual
(
obj
.
name
,
'target-4'
)
# Ensure (target 4, target_source 4, source 4) are added, and
# everything else is as expected.
queryset
=
OneToOneTarget
.
objects
.
all
()
serializer
=
self
.
Serializer
(
queryset
,
many
=
True
)
expected
=
[
{
'id'
:
1
,
'name'
:
'target-1'
,
'source'
:
{
'id'
:
1
,
'name'
:
'source-1'
}},
{
'id'
:
2
,
'name'
:
'target-2'
,
'source'
:
{
'id'
:
2
,
'name'
:
'source-2'
}},
{
'id'
:
3
,
'name'
:
'target-3'
,
'source'
:
{
'id'
:
3
,
'name'
:
'source-3'
}},
{
'id'
:
4
,
'name'
:
'target-4'
,
'source'
:
{
'id'
:
4
,
'name'
:
'source-4'
}}
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
def
test_one_to_one_create_with_invalid_data
(
self
):
data
=
{
'id'
:
4
,
'name'
:
'target-4'
,
'source'
:
{
'id'
:
4
}}
serializer
=
self
.
Serializer
(
data
=
data
)
self
.
assertFalse
(
serializer
.
is_valid
())
self
.
assertEqual
(
serializer
.
errors
,
{
'source'
:
[{
'name'
:
[
'This field is required.'
]}]})
def
test_one_to_one_update
(
self
):
data
=
{
'id'
:
3
,
'name'
:
'target-3-updated'
,
'source'
:
{
'id'
:
3
,
'name'
:
'source-3-updated'
}}
instance
=
OneToOneTarget
.
objects
.
get
(
pk
=
3
)
serializer
=
self
.
Serializer
(
instance
,
data
=
data
)
self
.
assertTrue
(
serializer
.
is_valid
())
obj
=
serializer
.
save
()
self
.
assertEqual
(
serializer
.
data
,
data
)
self
.
assertEqual
(
obj
.
name
,
'target-3-updated'
)
# Ensure (target 3, target_source 3, source 3) are updated,
# and everything else is as expected.
queryset
=
OneToOneTarget
.
objects
.
all
()
serializer
=
self
.
Serializer
(
queryset
,
many
=
True
)
expected
=
[
{
'id'
:
1
,
'name'
:
'target-1'
,
'source'
:
{
'id'
:
1
,
'name'
:
'source-1'
}},
{
'id'
:
2
,
'name'
:
'target-2'
,
'source'
:
{
'id'
:
2
,
'name'
:
'source-2'
}},
{
'id'
:
3
,
'name'
:
'target-3-updated'
,
'source'
:
{
'id'
:
3
,
'name'
:
'source-3-updated'
}}
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
class
ForwardNestedOneToOneTests
(
TestCase
):
def
setUp
(
self
):
class
OneToOneTargetSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
OneToOneTarget
fields
=
(
'id'
,
'name'
)
class
OneToOneSourceSerializer
(
serializers
.
ModelSerializer
):
target
=
OneToOneTargetSerializer
()
class
Meta
:
model
=
OneToOneSource
fields
=
(
'id'
,
'name'
,
'target'
)
self
.
Serializer
=
OneToOneSourceSerializer
for
idx
in
range
(
1
,
4
):
target
=
OneToOneTarget
(
name
=
'target-
%
d'
%
idx
)
target
.
save
()
source
=
OneToOneSource
(
name
=
'source-
%
d'
%
idx
,
target
=
target
)
source
.
save
()
def
test_one_to_one_retrieve
(
self
):
queryset
=
OneToOneSource
.
objects
.
all
()
serializer
=
self
.
Serializer
(
queryset
,
many
=
True
)
expected
=
[
{
'id'
:
1
,
'name'
:
'source-1'
,
'target'
:
{
'id'
:
1
,
'name'
:
'target-1'
}},
{
'id'
:
2
,
'name'
:
'source-2'
,
'target'
:
{
'id'
:
2
,
'name'
:
'target-2'
}},
{
'id'
:
3
,
'name'
:
'source-3'
,
'target'
:
{
'id'
:
3
,
'name'
:
'target-3'
}}
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
def
test_one_to_one_create
(
self
):
data
=
{
'id'
:
4
,
'name'
:
'source-4'
,
'target'
:
{
'id'
:
4
,
'name'
:
'target-4'
}}
serializer
=
self
.
Serializer
(
data
=
data
)
self
.
assertTrue
(
serializer
.
is_valid
())
obj
=
serializer
.
save
()
self
.
assertEqual
(
serializer
.
data
,
data
)
self
.
assertEqual
(
obj
.
name
,
'source-4'
)
# Ensure (target 4, target_source 4, source 4) are added, and
# everything else is as expected.
queryset
=
OneToOneSource
.
objects
.
all
()
serializer
=
self
.
Serializer
(
queryset
,
many
=
True
)
expected
=
[
{
'id'
:
1
,
'name'
:
'source-1'
,
'target'
:
{
'id'
:
1
,
'name'
:
'target-1'
}},
{
'id'
:
2
,
'name'
:
'source-2'
,
'target'
:
{
'id'
:
2
,
'name'
:
'target-2'
}},
{
'id'
:
3
,
'name'
:
'source-3'
,
'target'
:
{
'id'
:
3
,
'name'
:
'target-3'
}},
{
'id'
:
4
,
'name'
:
'source-4'
,
'target'
:
{
'id'
:
4
,
'name'
:
'target-4'
}}
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
def
test_one_to_one_create_with_invalid_data
(
self
):
data
=
{
'id'
:
4
,
'name'
:
'source-4'
,
'target'
:
{
'id'
:
4
}}
serializer
=
self
.
Serializer
(
data
=
data
)
self
.
assertFalse
(
serializer
.
is_valid
())
self
.
assertEqual
(
serializer
.
errors
,
{
'target'
:
[{
'name'
:
[
'This field is required.'
]}]})
def
test_one_to_one_update
(
self
):
data
=
{
'id'
:
3
,
'name'
:
'source-3-updated'
,
'target'
:
{
'id'
:
3
,
'name'
:
'target-3-updated'
}}
instance
=
OneToOneSource
.
objects
.
get
(
pk
=
3
)
serializer
=
self
.
Serializer
(
instance
,
data
=
data
)
self
.
assertTrue
(
serializer
.
is_valid
())
obj
=
serializer
.
save
()
self
.
assertEqual
(
serializer
.
data
,
data
)
self
.
assertEqual
(
obj
.
name
,
'source-3-updated'
)
# Ensure (target 3, target_source 3, source 3) are updated,
# and everything else is as expected.
queryset
=
OneToOneSource
.
objects
.
all
()
serializer
=
self
.
Serializer
(
queryset
,
many
=
True
)
expected
=
[
{
'id'
:
1
,
'name'
:
'source-1'
,
'target'
:
{
'id'
:
1
,
'name'
:
'target-1'
}},
{
'id'
:
2
,
'name'
:
'source-2'
,
'target'
:
{
'id'
:
2
,
'name'
:
'target-2'
}},
{
'id'
:
3
,
'name'
:
'source-3-updated'
,
'target'
:
{
'id'
:
3
,
'name'
:
'target-3-updated'
}}
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
def
test_one_to_one_update_to_null
(
self
):
data
=
{
'id'
:
3
,
'name'
:
'source-3-updated'
,
'target'
:
None
}
instance
=
OneToOneSource
.
objects
.
get
(
pk
=
3
)
serializer
=
self
.
Serializer
(
instance
,
data
=
data
)
self
.
assertTrue
(
serializer
.
is_valid
())
obj
=
serializer
.
save
()
self
.
assertEqual
(
serializer
.
data
,
data
)
self
.
assertEqual
(
obj
.
name
,
'source-3-updated'
)
self
.
assertEqual
(
obj
.
target
,
None
)
queryset
=
OneToOneSource
.
objects
.
all
()
serializer
=
self
.
Serializer
(
queryset
,
many
=
True
)
expected
=
[
{
'id'
:
1
,
'name'
:
'source-1'
,
'target'
:
{
'id'
:
1
,
'name'
:
'target-1'
}},
{
'id'
:
2
,
'name'
:
'source-2'
,
'target'
:
{
'id'
:
2
,
'name'
:
'target-2'
}},
{
'id'
:
3
,
'name'
:
'source-3-updated'
,
'target'
:
None
}
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
# TODO: Nullable 1-1 tests
# def test_one_to_one_delete(self):
# data = {'id': 3, 'name': 'target-3', 'target_source': None}
# instance = OneToOneTarget.objects.get(pk=3)
# serializer = self.Serializer(instance, data=data)
# self.assertTrue(serializer.is_valid())
# serializer.save()
# # Ensure (target_source 3, source 3) are deleted,
# # and everything else is as expected.
# queryset = OneToOneTarget.objects.all()
# serializer = self.Serializer(queryset)
# expected = [
# {'id': 1, 'name': 'target-1', 'source': {'id': 1, 'name': 'source-1'}},
# {'id': 2, 'name': 'target-2', 'source': {'id': 2, 'name': 'source-2'}},
# {'id': 3, 'name': 'target-3', 'source': None}
# ]
# self.assertEqual(serializer.data, expected)
class
ReverseNestedOneToManyTests
(
TestCase
):
def
setUp
(
self
):
class
OneToManySourceSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
OneToManySource
fields
=
(
'id'
,
'name'
)
class
OneToManyTargetSerializer
(
serializers
.
ModelSerializer
):
sources
=
OneToManySourceSerializer
(
many
=
True
,
allow_add_remove
=
True
)
class
Meta
:
model
=
OneToManyTarget
fields
=
(
'id'
,
'name'
,
'sources'
)
self
.
Serializer
=
OneToManyTargetSerializer
target
=
OneToManyTarget
(
name
=
'target-1'
)
target
.
save
()
for
idx
in
range
(
1
,
4
):
source
=
OneToManySource
(
name
=
'source-
%
d'
%
idx
,
target
=
target
)
source
.
save
()
def
test_one_to_many_retrieve
(
self
):
queryset
=
OneToManyTarget
.
objects
.
all
()
serializer
=
self
.
Serializer
(
queryset
,
many
=
True
)
expected
=
[
{
'id'
:
1
,
'name'
:
'target-1'
,
'sources'
:
[{
'id'
:
1
,
'name'
:
'source-1'
},
{
'id'
:
2
,
'name'
:
'source-2'
},
{
'id'
:
3
,
'name'
:
'source-3'
}]},
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
def
test_one_to_many_create
(
self
):
data
=
{
'id'
:
1
,
'name'
:
'target-1'
,
'sources'
:
[{
'id'
:
1
,
'name'
:
'source-1'
},
{
'id'
:
2
,
'name'
:
'source-2'
},
{
'id'
:
3
,
'name'
:
'source-3'
},
{
'id'
:
4
,
'name'
:
'source-4'
}]}
instance
=
OneToManyTarget
.
objects
.
get
(
pk
=
1
)
serializer
=
self
.
Serializer
(
instance
,
data
=
data
)
self
.
assertTrue
(
serializer
.
is_valid
())
obj
=
serializer
.
save
()
self
.
assertEqual
(
serializer
.
data
,
data
)
self
.
assertEqual
(
obj
.
name
,
'target-1'
)
# Ensure source 4 is added, and everything else is as
# expected.
queryset
=
OneToManyTarget
.
objects
.
all
()
serializer
=
self
.
Serializer
(
queryset
,
many
=
True
)
expected
=
[
{
'id'
:
1
,
'name'
:
'target-1'
,
'sources'
:
[{
'id'
:
1
,
'name'
:
'source-1'
},
{
'id'
:
2
,
'name'
:
'source-2'
},
{
'id'
:
3
,
'name'
:
'source-3'
},
{
'id'
:
4
,
'name'
:
'source-4'
}]}
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
def
test_one_to_many_create_with_invalid_data
(
self
):
data
=
{
'id'
:
1
,
'name'
:
'target-1'
,
'sources'
:
[{
'id'
:
1
,
'name'
:
'source-1'
},
{
'id'
:
2
,
'name'
:
'source-2'
},
{
'id'
:
3
,
'name'
:
'source-3'
},
{
'id'
:
4
}]}
serializer
=
self
.
Serializer
(
data
=
data
)
self
.
assertFalse
(
serializer
.
is_valid
())
self
.
assertEqual
(
serializer
.
errors
,
{
'sources'
:
[{},
{},
{},
{
'name'
:
[
'This field is required.'
]}]})
def
test_one_to_many_update
(
self
):
data
=
{
'id'
:
1
,
'name'
:
'target-1-updated'
,
'sources'
:
[{
'id'
:
1
,
'name'
:
'source-1-updated'
},
{
'id'
:
2
,
'name'
:
'source-2'
},
{
'id'
:
3
,
'name'
:
'source-3'
}]}
instance
=
OneToManyTarget
.
objects
.
get
(
pk
=
1
)
serializer
=
self
.
Serializer
(
instance
,
data
=
data
)
self
.
assertTrue
(
serializer
.
is_valid
())
obj
=
serializer
.
save
()
self
.
assertEqual
(
serializer
.
data
,
data
)
self
.
assertEqual
(
obj
.
name
,
'target-1-updated'
)
# Ensure (target 1, source 1) are updated,
# and everything else is as expected.
queryset
=
OneToManyTarget
.
objects
.
all
()
serializer
=
self
.
Serializer
(
queryset
,
many
=
True
)
expected
=
[
{
'id'
:
1
,
'name'
:
'target-1-updated'
,
'sources'
:
[{
'id'
:
1
,
'name'
:
'source-1-updated'
},
{
'id'
:
2
,
'name'
:
'source-2'
},
{
'id'
:
3
,
'name'
:
'source-3'
}]}
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
def
test_one_to_many_delete
(
self
):
data
=
{
'id'
:
1
,
'name'
:
'target-1'
,
'sources'
:
[{
'id'
:
1
,
'name'
:
'source-1'
},
{
'id'
:
3
,
'name'
:
'source-3'
}]}
instance
=
OneToManyTarget
.
objects
.
get
(
pk
=
1
)
serializer
=
self
.
Serializer
(
instance
,
data
=
data
)
self
.
assertTrue
(
serializer
.
is_valid
())
serializer
.
save
()
# Ensure source 2 is deleted, and everything else is as
# expected.
queryset
=
OneToManyTarget
.
objects
.
all
()
serializer
=
self
.
Serializer
(
queryset
,
many
=
True
)
expected
=
[
{
'id'
:
1
,
'name'
:
'target-1'
,
'sources'
:
[{
'id'
:
1
,
'name'
:
'source-1'
},
{
'id'
:
3
,
'name'
:
'source-3'
}]}
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
#
from __future__ import unicode_literals
#
from django.db import models
#
from django.test import TestCase
#
from rest_framework import serializers
#
from .models import OneToOneTarget
#
class OneToOneSource(models.Model):
#
name = models.CharField(max_length=100)
#
target = models.OneToOneField(OneToOneTarget, related_name='source',
#
null=True, blank=True)
#
class OneToManyTarget(models.Model):
#
name = models.CharField(max_length=100)
#
class OneToManySource(models.Model):
#
name = models.CharField(max_length=100)
#
target = models.ForeignKey(OneToManyTarget, related_name='sources')
#
class ReverseNestedOneToOneTests(TestCase):
#
def setUp(self):
#
class OneToOneSourceSerializer(serializers.ModelSerializer):
#
class Meta:
#
model = OneToOneSource
#
fields = ('id', 'name')
#
class OneToOneTargetSerializer(serializers.ModelSerializer):
#
source = OneToOneSourceSerializer()
#
class Meta:
#
model = OneToOneTarget
#
fields = ('id', 'name', 'source')
#
self.Serializer = OneToOneTargetSerializer
#
for idx in range(1, 4):
#
target = OneToOneTarget(name='target-%d' % idx)
#
target.save()
#
source = OneToOneSource(name='source-%d' % idx, target=target)
#
source.save()
#
def test_one_to_one_retrieve(self):
#
queryset = OneToOneTarget.objects.all()
#
serializer = self.Serializer(queryset, many=True)
#
expected = [
#
{'id': 1, 'name': 'target-1', 'source': {'id': 1, 'name': 'source-1'}},
#
{'id': 2, 'name': 'target-2', 'source': {'id': 2, 'name': 'source-2'}},
#
{'id': 3, 'name': 'target-3', 'source': {'id': 3, 'name': 'source-3'}}
#
]
#
self.assertEqual(serializer.data, expected)
#
def test_one_to_one_create(self):
#
data = {'id': 4, 'name': 'target-4', 'source': {'id': 4, 'name': 'source-4'}}
#
serializer = self.Serializer(data=data)
#
self.assertTrue(serializer.is_valid())
#
obj = serializer.save()
#
self.assertEqual(serializer.data, data)
#
self.assertEqual(obj.name, 'target-4')
#
# Ensure (target 4, target_source 4, source 4) are added, and
#
# everything else is as expected.
#
queryset = OneToOneTarget.objects.all()
#
serializer = self.Serializer(queryset, many=True)
#
expected = [
#
{'id': 1, 'name': 'target-1', 'source': {'id': 1, 'name': 'source-1'}},
#
{'id': 2, 'name': 'target-2', 'source': {'id': 2, 'name': 'source-2'}},
#
{'id': 3, 'name': 'target-3', 'source': {'id': 3, 'name': 'source-3'}},
#
{'id': 4, 'name': 'target-4', 'source': {'id': 4, 'name': 'source-4'}}
#
]
#
self.assertEqual(serializer.data, expected)
#
def test_one_to_one_create_with_invalid_data(self):
#
data = {'id': 4, 'name': 'target-4', 'source': {'id': 4}}
#
serializer = self.Serializer(data=data)
#
self.assertFalse(serializer.is_valid())
#
self.assertEqual(serializer.errors, {'source': [{'name': ['This field is required.']}]})
#
def test_one_to_one_update(self):
#
data = {'id': 3, 'name': 'target-3-updated', 'source': {'id': 3, 'name': 'source-3-updated'}}
#
instance = OneToOneTarget.objects.get(pk=3)
#
serializer = self.Serializer(instance, data=data)
#
self.assertTrue(serializer.is_valid())
#
obj = serializer.save()
#
self.assertEqual(serializer.data, data)
#
self.assertEqual(obj.name, 'target-3-updated')
#
# Ensure (target 3, target_source 3, source 3) are updated,
#
# and everything else is as expected.
#
queryset = OneToOneTarget.objects.all()
#
serializer = self.Serializer(queryset, many=True)
#
expected = [
#
{'id': 1, 'name': 'target-1', 'source': {'id': 1, 'name': 'source-1'}},
#
{'id': 2, 'name': 'target-2', 'source': {'id': 2, 'name': 'source-2'}},
#
{'id': 3, 'name': 'target-3-updated', 'source': {'id': 3, 'name': 'source-3-updated'}}
#
]
#
self.assertEqual(serializer.data, expected)
#
class ForwardNestedOneToOneTests(TestCase):
#
def setUp(self):
#
class OneToOneTargetSerializer(serializers.ModelSerializer):
#
class Meta:
#
model = OneToOneTarget
#
fields = ('id', 'name')
#
class OneToOneSourceSerializer(serializers.ModelSerializer):
#
target = OneToOneTargetSerializer()
#
class Meta:
#
model = OneToOneSource
#
fields = ('id', 'name', 'target')
#
self.Serializer = OneToOneSourceSerializer
#
for idx in range(1, 4):
#
target = OneToOneTarget(name='target-%d' % idx)
#
target.save()
#
source = OneToOneSource(name='source-%d' % idx, target=target)
#
source.save()
#
def test_one_to_one_retrieve(self):
#
queryset = OneToOneSource.objects.all()
#
serializer = self.Serializer(queryset, many=True)
#
expected = [
#
{'id': 1, 'name': 'source-1', 'target': {'id': 1, 'name': 'target-1'}},
#
{'id': 2, 'name': 'source-2', 'target': {'id': 2, 'name': 'target-2'}},
#
{'id': 3, 'name': 'source-3', 'target': {'id': 3, 'name': 'target-3'}}
#
]
#
self.assertEqual(serializer.data, expected)
#
def test_one_to_one_create(self):
#
data = {'id': 4, 'name': 'source-4', 'target': {'id': 4, 'name': 'target-4'}}
#
serializer = self.Serializer(data=data)
#
self.assertTrue(serializer.is_valid())
#
obj = serializer.save()
#
self.assertEqual(serializer.data, data)
#
self.assertEqual(obj.name, 'source-4')
#
# Ensure (target 4, target_source 4, source 4) are added, and
#
# everything else is as expected.
#
queryset = OneToOneSource.objects.all()
#
serializer = self.Serializer(queryset, many=True)
#
expected = [
#
{'id': 1, 'name': 'source-1', 'target': {'id': 1, 'name': 'target-1'}},
#
{'id': 2, 'name': 'source-2', 'target': {'id': 2, 'name': 'target-2'}},
#
{'id': 3, 'name': 'source-3', 'target': {'id': 3, 'name': 'target-3'}},
#
{'id': 4, 'name': 'source-4', 'target': {'id': 4, 'name': 'target-4'}}
#
]
#
self.assertEqual(serializer.data, expected)
#
def test_one_to_one_create_with_invalid_data(self):
#
data = {'id': 4, 'name': 'source-4', 'target': {'id': 4}}
#
serializer = self.Serializer(data=data)
#
self.assertFalse(serializer.is_valid())
#
self.assertEqual(serializer.errors, {'target': [{'name': ['This field is required.']}]})
#
def test_one_to_one_update(self):
#
data = {'id': 3, 'name': 'source-3-updated', 'target': {'id': 3, 'name': 'target-3-updated'}}
#
instance = OneToOneSource.objects.get(pk=3)
#
serializer = self.Serializer(instance, data=data)
#
self.assertTrue(serializer.is_valid())
#
obj = serializer.save()
#
self.assertEqual(serializer.data, data)
#
self.assertEqual(obj.name, 'source-3-updated')
#
# Ensure (target 3, target_source 3, source 3) are updated,
#
# and everything else is as expected.
#
queryset = OneToOneSource.objects.all()
#
serializer = self.Serializer(queryset, many=True)
#
expected = [
#
{'id': 1, 'name': 'source-1', 'target': {'id': 1, 'name': 'target-1'}},
#
{'id': 2, 'name': 'source-2', 'target': {'id': 2, 'name': 'target-2'}},
#
{'id': 3, 'name': 'source-3-updated', 'target': {'id': 3, 'name': 'target-3-updated'}}
#
]
#
self.assertEqual(serializer.data, expected)
#
def test_one_to_one_update_to_null(self):
#
data = {'id': 3, 'name': 'source-3-updated', 'target': None}
#
instance = OneToOneSource.objects.get(pk=3)
#
serializer = self.Serializer(instance, data=data)
#
self.assertTrue(serializer.is_valid())
#
obj = serializer.save()
#
self.assertEqual(serializer.data, data)
#
self.assertEqual(obj.name, 'source-3-updated')
#
self.assertEqual(obj.target, None)
#
queryset = OneToOneSource.objects.all()
#
serializer = self.Serializer(queryset, many=True)
#
expected = [
#
{'id': 1, 'name': 'source-1', 'target': {'id': 1, 'name': 'target-1'}},
#
{'id': 2, 'name': 'source-2', 'target': {'id': 2, 'name': 'target-2'}},
#
{'id': 3, 'name': 'source-3-updated', 'target': None}
#
]
#
self.assertEqual(serializer.data, expected)
#
# TODO: Nullable 1-1 tests
#
# def test_one_to_one_delete(self):
#
# data = {'id': 3, 'name': 'target-3', 'target_source': None}
#
# instance = OneToOneTarget.objects.get(pk=3)
#
# serializer = self.Serializer(instance, data=data)
#
# self.assertTrue(serializer.is_valid())
#
# serializer.save()
#
# # Ensure (target_source 3, source 3) are deleted,
#
# # and everything else is as expected.
#
# queryset = OneToOneTarget.objects.all()
#
# serializer = self.Serializer(queryset)
#
# expected = [
#
# {'id': 1, 'name': 'target-1', 'source': {'id': 1, 'name': 'source-1'}},
#
# {'id': 2, 'name': 'target-2', 'source': {'id': 2, 'name': 'source-2'}},
#
# {'id': 3, 'name': 'target-3', 'source': None}
#
# ]
#
# self.assertEqual(serializer.data, expected)
#
class ReverseNestedOneToManyTests(TestCase):
#
def setUp(self):
#
class OneToManySourceSerializer(serializers.ModelSerializer):
#
class Meta:
#
model = OneToManySource
#
fields = ('id', 'name')
#
class OneToManyTargetSerializer(serializers.ModelSerializer):
#
sources = OneToManySourceSerializer(many=True, allow_add_remove=True)
#
class Meta:
#
model = OneToManyTarget
#
fields = ('id', 'name', 'sources')
#
self.Serializer = OneToManyTargetSerializer
#
target = OneToManyTarget(name='target-1')
#
target.save()
#
for idx in range(1, 4):
#
source = OneToManySource(name='source-%d' % idx, target=target)
#
source.save()
#
def test_one_to_many_retrieve(self):
#
queryset = OneToManyTarget.objects.all()
#
serializer = self.Serializer(queryset, many=True)
#
expected = [
#
{'id': 1, 'name': 'target-1', 'sources': [{'id': 1, 'name': 'source-1'},
#
{'id': 2, 'name': 'source-2'},
#
{'id': 3, 'name': 'source-3'}]},
#
]
#
self.assertEqual(serializer.data, expected)
#
def test_one_to_many_create(self):
#
data = {'id': 1, 'name': 'target-1', 'sources': [{'id': 1, 'name': 'source-1'},
#
{'id': 2, 'name': 'source-2'},
#
{'id': 3, 'name': 'source-3'},
#
{'id': 4, 'name': 'source-4'}]}
#
instance = OneToManyTarget.objects.get(pk=1)
#
serializer = self.Serializer(instance, data=data)
#
self.assertTrue(serializer.is_valid())
#
obj = serializer.save()
#
self.assertEqual(serializer.data, data)
#
self.assertEqual(obj.name, 'target-1')
#
# Ensure source 4 is added, and everything else is as
#
# expected.
#
queryset = OneToManyTarget.objects.all()
#
serializer = self.Serializer(queryset, many=True)
#
expected = [
#
{'id': 1, 'name': 'target-1', 'sources': [{'id': 1, 'name': 'source-1'},
#
{'id': 2, 'name': 'source-2'},
#
{'id': 3, 'name': 'source-3'},
#
{'id': 4, 'name': 'source-4'}]}
#
]
#
self.assertEqual(serializer.data, expected)
#
def test_one_to_many_create_with_invalid_data(self):
#
data = {'id': 1, 'name': 'target-1', 'sources': [{'id': 1, 'name': 'source-1'},
#
{'id': 2, 'name': 'source-2'},
#
{'id': 3, 'name': 'source-3'},
#
{'id': 4}]}
#
serializer = self.Serializer(data=data)
#
self.assertFalse(serializer.is_valid())
#
self.assertEqual(serializer.errors, {'sources': [{}, {}, {}, {'name': ['This field is required.']}]})
#
def test_one_to_many_update(self):
#
data = {'id': 1, 'name': 'target-1-updated', 'sources': [{'id': 1, 'name': 'source-1-updated'},
#
{'id': 2, 'name': 'source-2'},
#
{'id': 3, 'name': 'source-3'}]}
#
instance = OneToManyTarget.objects.get(pk=1)
#
serializer = self.Serializer(instance, data=data)
#
self.assertTrue(serializer.is_valid())
#
obj = serializer.save()
#
self.assertEqual(serializer.data, data)
#
self.assertEqual(obj.name, 'target-1-updated')
#
# Ensure (target 1, source 1) are updated,
#
# and everything else is as expected.
#
queryset = OneToManyTarget.objects.all()
#
serializer = self.Serializer(queryset, many=True)
#
expected = [
#
{'id': 1, 'name': 'target-1-updated', 'sources': [{'id': 1, 'name': 'source-1-updated'},
#
{'id': 2, 'name': 'source-2'},
#
{'id': 3, 'name': 'source-3'}]}
#
]
#
self.assertEqual(serializer.data, expected)
#
def test_one_to_many_delete(self):
#
data = {'id': 1, 'name': 'target-1', 'sources': [{'id': 1, 'name': 'source-1'},
#
{'id': 3, 'name': 'source-3'}]}
#
instance = OneToManyTarget.objects.get(pk=1)
#
serializer = self.Serializer(instance, data=data)
#
self.assertTrue(serializer.is_valid())
#
serializer.save()
#
# Ensure source 2 is deleted, and everything else is as
#
# expected.
#
queryset = OneToManyTarget.objects.all()
#
serializer = self.Serializer(queryset, many=True)
#
expected = [
#
{'id': 1, 'name': 'target-1', 'sources': [{'id': 1, 'name': 'source-1'},
#
{'id': 3, 'name': 'source-3'}]}
#
]
#
self.assertEqual(serializer.data, expected)
tests/test_relations_pk.py
View file @
f2852811
from
__future__
import
unicode_literals
from
django.db
import
models
from
django.test
import
TestCase
from
django.utils
import
six
from
rest_framework
import
serializers
from
tests.models
import
(
BlogPost
,
ManyToManyTarget
,
ManyToManySource
,
ForeignKeyTarget
,
ForeignKeySource
,
NullableForeignKeySource
,
OneToOneTarget
,
NullableOneToOneSource
,
)
# ManyToMany
class
ManyToManyTargetSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
ManyToManyTarget
fields
=
(
'id'
,
'name'
,
'sources'
)
class
ManyToManySourceSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
ManyToManySource
fields
=
(
'id'
,
'name'
,
'targets'
)
# ForeignKey
class
ForeignKeyTargetSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
ForeignKeyTarget
fields
=
(
'id'
,
'name'
,
'sources'
)
class
ForeignKeySourceSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
ForeignKeySource
fields
=
(
'id'
,
'name'
,
'target'
)
# Nullable ForeignKey
class
NullableForeignKeySourceSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
NullableForeignKeySource
fields
=
(
'id'
,
'name'
,
'target'
)
# Nullable OneToOne
class
NullableOneToOneTargetSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
OneToOneTarget
fields
=
(
'id'
,
'name'
,
'nullable_source'
)
# TODO: Add test that .data cannot be accessed prior to .is_valid
class
PKManyToManyTests
(
TestCase
):
def
setUp
(
self
):
for
idx
in
range
(
1
,
4
):
target
=
ManyToManyTarget
(
name
=
'target-
%
d'
%
idx
)
target
.
save
()
source
=
ManyToManySource
(
name
=
'source-
%
d'
%
idx
)
source
.
save
()
for
target
in
ManyToManyTarget
.
objects
.
all
():
source
.
targets
.
add
(
target
)
def
test_many_to_many_retrieve
(
self
):
queryset
=
ManyToManySource
.
objects
.
all
()
serializer
=
ManyToManySourceSerializer
(
queryset
,
many
=
True
)
expected
=
[
{
'id'
:
1
,
'name'
:
'source-1'
,
'targets'
:
[
1
]},
{
'id'
:
2
,
'name'
:
'source-2'
,
'targets'
:
[
1
,
2
]},
{
'id'
:
3
,
'name'
:
'source-3'
,
'targets'
:
[
1
,
2
,
3
]}
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
def
test_reverse_many_to_many_retrieve
(
self
):
queryset
=
ManyToManyTarget
.
objects
.
all
()
serializer
=
ManyToManyTargetSerializer
(
queryset
,
many
=
True
)
expected
=
[
{
'id'
:
1
,
'name'
:
'target-1'
,
'sources'
:
[
1
,
2
,
3
]},
{
'id'
:
2
,
'name'
:
'target-2'
,
'sources'
:
[
2
,
3
]},
{
'id'
:
3
,
'name'
:
'target-3'
,
'sources'
:
[
3
]}
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
def
test_many_to_many_update
(
self
):
data
=
{
'id'
:
1
,
'name'
:
'source-1'
,
'targets'
:
[
1
,
2
,
3
]}
instance
=
ManyToManySource
.
objects
.
get
(
pk
=
1
)
serializer
=
ManyToManySourceSerializer
(
instance
,
data
=
data
)
self
.
assertTrue
(
serializer
.
is_valid
())
serializer
.
save
()
self
.
assertEqual
(
serializer
.
data
,
data
)
# Ensure source 1 is updated, and everything else is as expected
queryset
=
ManyToManySource
.
objects
.
all
()
serializer
=
ManyToManySourceSerializer
(
queryset
,
many
=
True
)
expected
=
[
{
'id'
:
1
,
'name'
:
'source-1'
,
'targets'
:
[
1
,
2
,
3
]},
{
'id'
:
2
,
'name'
:
'source-2'
,
'targets'
:
[
1
,
2
]},
{
'id'
:
3
,
'name'
:
'source-3'
,
'targets'
:
[
1
,
2
,
3
]}
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
def
test_reverse_many_to_many_update
(
self
):
data
=
{
'id'
:
1
,
'name'
:
'target-1'
,
'sources'
:
[
1
]}
instance
=
ManyToManyTarget
.
objects
.
get
(
pk
=
1
)
serializer
=
ManyToManyTargetSerializer
(
instance
,
data
=
data
)
self
.
assertTrue
(
serializer
.
is_valid
())
serializer
.
save
()
self
.
assertEqual
(
serializer
.
data
,
data
)
# Ensure target 1 is updated, and everything else is as expected
queryset
=
ManyToManyTarget
.
objects
.
all
()
serializer
=
ManyToManyTargetSerializer
(
queryset
,
many
=
True
)
expected
=
[
{
'id'
:
1
,
'name'
:
'target-1'
,
'sources'
:
[
1
]},
{
'id'
:
2
,
'name'
:
'target-2'
,
'sources'
:
[
2
,
3
]},
{
'id'
:
3
,
'name'
:
'target-3'
,
'sources'
:
[
3
]}
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
def
test_many_to_many_create
(
self
):
data
=
{
'id'
:
4
,
'name'
:
'source-4'
,
'targets'
:
[
1
,
3
]}
serializer
=
ManyToManySourceSerializer
(
data
=
data
)
self
.
assertTrue
(
serializer
.
is_valid
())
obj
=
serializer
.
save
()
self
.
assertEqual
(
serializer
.
data
,
data
)
self
.
assertEqual
(
obj
.
name
,
'source-4'
)
# Ensure source 4 is added, and everything else is as expected
queryset
=
ManyToManySource
.
objects
.
all
()
serializer
=
ManyToManySourceSerializer
(
queryset
,
many
=
True
)
self
.
assertFalse
(
serializer
.
fields
[
'targets'
]
.
read_only
)
expected
=
[
{
'id'
:
1
,
'name'
:
'source-1'
,
'targets'
:
[
1
]},
{
'id'
:
2
,
'name'
:
'source-2'
,
'targets'
:
[
1
,
2
]},
{
'id'
:
3
,
'name'
:
'source-3'
,
'targets'
:
[
1
,
2
,
3
]},
{
'id'
:
4
,
'name'
:
'source-4'
,
'targets'
:
[
1
,
3
]},
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
def
test_reverse_many_to_many_create
(
self
):
data
=
{
'id'
:
4
,
'name'
:
'target-4'
,
'sources'
:
[
1
,
3
]}
serializer
=
ManyToManyTargetSerializer
(
data
=
data
)
self
.
assertFalse
(
serializer
.
fields
[
'sources'
]
.
read_only
)
self
.
assertTrue
(
serializer
.
is_valid
())
obj
=
serializer
.
save
()
self
.
assertEqual
(
serializer
.
data
,
data
)
self
.
assertEqual
(
obj
.
name
,
'target-4'
)
# Ensure target 4 is added, and everything else is as expected
queryset
=
ManyToManyTarget
.
objects
.
all
()
serializer
=
ManyToManyTargetSerializer
(
queryset
,
many
=
True
)
expected
=
[
{
'id'
:
1
,
'name'
:
'target-1'
,
'sources'
:
[
1
,
2
,
3
]},
{
'id'
:
2
,
'name'
:
'target-2'
,
'sources'
:
[
2
,
3
]},
{
'id'
:
3
,
'name'
:
'target-3'
,
'sources'
:
[
3
]},
{
'id'
:
4
,
'name'
:
'target-4'
,
'sources'
:
[
1
,
3
]}
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
class
PKForeignKeyTests
(
TestCase
):
def
setUp
(
self
):
target
=
ForeignKeyTarget
(
name
=
'target-1'
)
target
.
save
()
new_target
=
ForeignKeyTarget
(
name
=
'target-2'
)
new_target
.
save
()
for
idx
in
range
(
1
,
4
):
source
=
ForeignKeySource
(
name
=
'source-
%
d'
%
idx
,
target
=
target
)
source
.
save
()
def
test_foreign_key_retrieve
(
self
):
queryset
=
ForeignKeySource
.
objects
.
all
()
serializer
=
ForeignKeySourceSerializer
(
queryset
,
many
=
True
)
expected
=
[
{
'id'
:
1
,
'name'
:
'source-1'
,
'target'
:
1
},
{
'id'
:
2
,
'name'
:
'source-2'
,
'target'
:
1
},
{
'id'
:
3
,
'name'
:
'source-3'
,
'target'
:
1
}
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
def
test_reverse_foreign_key_retrieve
(
self
):
queryset
=
ForeignKeyTarget
.
objects
.
all
()
serializer
=
ForeignKeyTargetSerializer
(
queryset
,
many
=
True
)
expected
=
[
{
'id'
:
1
,
'name'
:
'target-1'
,
'sources'
:
[
1
,
2
,
3
]},
{
'id'
:
2
,
'name'
:
'target-2'
,
'sources'
:
[]},
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
def
test_foreign_key_update
(
self
):
data
=
{
'id'
:
1
,
'name'
:
'source-1'
,
'target'
:
2
}
instance
=
ForeignKeySource
.
objects
.
get
(
pk
=
1
)
serializer
=
ForeignKeySourceSerializer
(
instance
,
data
=
data
)
self
.
assertTrue
(
serializer
.
is_valid
())
self
.
assertEqual
(
serializer
.
data
,
data
)
serializer
.
save
()
# Ensure source 1 is updated, and everything else is as expected
queryset
=
ForeignKeySource
.
objects
.
all
()
serializer
=
ForeignKeySourceSerializer
(
queryset
,
many
=
True
)
expected
=
[
{
'id'
:
1
,
'name'
:
'source-1'
,
'target'
:
2
},
{
'id'
:
2
,
'name'
:
'source-2'
,
'target'
:
1
},
{
'id'
:
3
,
'name'
:
'source-3'
,
'target'
:
1
}
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
def
test_foreign_key_update_incorrect_type
(
self
):
data
=
{
'id'
:
1
,
'name'
:
'source-1'
,
'target'
:
'foo'
}
instance
=
ForeignKeySource
.
objects
.
get
(
pk
=
1
)
serializer
=
ForeignKeySourceSerializer
(
instance
,
data
=
data
)
self
.
assertFalse
(
serializer
.
is_valid
())
self
.
assertEqual
(
serializer
.
errors
,
{
'target'
:
[
'Incorrect type. Expected pk value, received
%
s.'
%
six
.
text_type
.
__name__
]})
def
test_reverse_foreign_key_update
(
self
):
data
=
{
'id'
:
2
,
'name'
:
'target-2'
,
'sources'
:
[
1
,
3
]}
instance
=
ForeignKeyTarget
.
objects
.
get
(
pk
=
2
)
serializer
=
ForeignKeyTargetSerializer
(
instance
,
data
=
data
)
self
.
assertTrue
(
serializer
.
is_valid
())
# We shouldn't have saved anything to the db yet since save
# hasn't been called.
queryset
=
ForeignKeyTarget
.
objects
.
all
()
new_serializer
=
ForeignKeyTargetSerializer
(
queryset
,
many
=
True
)
expected
=
[
{
'id'
:
1
,
'name'
:
'target-1'
,
'sources'
:
[
1
,
2
,
3
]},
{
'id'
:
2
,
'name'
:
'target-2'
,
'sources'
:
[]},
]
self
.
assertEqual
(
new_serializer
.
data
,
expected
)
serializer
.
save
()
self
.
assertEqual
(
serializer
.
data
,
data
)
# Ensure target 2 is update, and everything else is as expected
queryset
=
ForeignKeyTarget
.
objects
.
all
()
serializer
=
ForeignKeyTargetSerializer
(
queryset
,
many
=
True
)
expected
=
[
{
'id'
:
1
,
'name'
:
'target-1'
,
'sources'
:
[
2
]},
{
'id'
:
2
,
'name'
:
'target-2'
,
'sources'
:
[
1
,
3
]},
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
def
test_foreign_key_create
(
self
):
data
=
{
'id'
:
4
,
'name'
:
'source-4'
,
'target'
:
2
}
serializer
=
ForeignKeySourceSerializer
(
data
=
data
)
self
.
assertTrue
(
serializer
.
is_valid
())
obj
=
serializer
.
save
()
self
.
assertEqual
(
serializer
.
data
,
data
)
self
.
assertEqual
(
obj
.
name
,
'source-4'
)
# Ensure source 4 is added, and everything else is as expected
queryset
=
ForeignKeySource
.
objects
.
all
()
serializer
=
ForeignKeySourceSerializer
(
queryset
,
many
=
True
)
expected
=
[
{
'id'
:
1
,
'name'
:
'source-1'
,
'target'
:
1
},
{
'id'
:
2
,
'name'
:
'source-2'
,
'target'
:
1
},
{
'id'
:
3
,
'name'
:
'source-3'
,
'target'
:
1
},
{
'id'
:
4
,
'name'
:
'source-4'
,
'target'
:
2
},
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
def
test_reverse_foreign_key_create
(
self
):
data
=
{
'id'
:
3
,
'name'
:
'target-3'
,
'sources'
:
[
1
,
3
]}
serializer
=
ForeignKeyTargetSerializer
(
data
=
data
)
self
.
assertTrue
(
serializer
.
is_valid
())
obj
=
serializer
.
save
()
self
.
assertEqual
(
serializer
.
data
,
data
)
self
.
assertEqual
(
obj
.
name
,
'target-3'
)
# Ensure target 3 is added, and everything else is as expected
queryset
=
ForeignKeyTarget
.
objects
.
all
()
serializer
=
ForeignKeyTargetSerializer
(
queryset
,
many
=
True
)
expected
=
[
{
'id'
:
1
,
'name'
:
'target-1'
,
'sources'
:
[
2
]},
{
'id'
:
2
,
'name'
:
'target-2'
,
'sources'
:
[]},
{
'id'
:
3
,
'name'
:
'target-3'
,
'sources'
:
[
1
,
3
]},
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
def
test_foreign_key_update_with_invalid_null
(
self
):
data
=
{
'id'
:
1
,
'name'
:
'source-1'
,
'target'
:
None
}
instance
=
ForeignKeySource
.
objects
.
get
(
pk
=
1
)
serializer
=
ForeignKeySourceSerializer
(
instance
,
data
=
data
)
self
.
assertFalse
(
serializer
.
is_valid
())
self
.
assertEqual
(
serializer
.
errors
,
{
'target'
:
[
'This field is required.'
]})
def
test_foreign_key_with_empty
(
self
):
"""
Regression test for #1072
https://github.com/tomchristie/django-rest-framework/issues/1072
"""
serializer
=
NullableForeignKeySourceSerializer
()
self
.
assertEqual
(
serializer
.
data
[
'target'
],
None
)
class
PKNullableForeignKeyTests
(
TestCase
):
def
setUp
(
self
):
target
=
ForeignKeyTarget
(
name
=
'target-1'
)
target
.
save
()
for
idx
in
range
(
1
,
4
):
if
idx
==
3
:
target
=
None
source
=
NullableForeignKeySource
(
name
=
'source-
%
d'
%
idx
,
target
=
target
)
source
.
save
()
def
test_foreign_key_retrieve_with_null
(
self
):
queryset
=
NullableForeignKeySource
.
objects
.
all
()
serializer
=
NullableForeignKeySourceSerializer
(
queryset
,
many
=
True
)
expected
=
[
{
'id'
:
1
,
'name'
:
'source-1'
,
'target'
:
1
},
{
'id'
:
2
,
'name'
:
'source-2'
,
'target'
:
1
},
{
'id'
:
3
,
'name'
:
'source-3'
,
'target'
:
None
},
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
def
test_foreign_key_create_with_valid_null
(
self
):
data
=
{
'id'
:
4
,
'name'
:
'source-4'
,
'target'
:
None
}
serializer
=
NullableForeignKeySourceSerializer
(
data
=
data
)
self
.
assertTrue
(
serializer
.
is_valid
())
obj
=
serializer
.
save
()
self
.
assertEqual
(
serializer
.
data
,
data
)
self
.
assertEqual
(
obj
.
name
,
'source-4'
)
# Ensure source 4 is created, and everything else is as expected
queryset
=
NullableForeignKeySource
.
objects
.
all
()
serializer
=
NullableForeignKeySourceSerializer
(
queryset
,
many
=
True
)
expected
=
[
{
'id'
:
1
,
'name'
:
'source-1'
,
'target'
:
1
},
{
'id'
:
2
,
'name'
:
'source-2'
,
'target'
:
1
},
{
'id'
:
3
,
'name'
:
'source-3'
,
'target'
:
None
},
{
'id'
:
4
,
'name'
:
'source-4'
,
'target'
:
None
}
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
def
test_foreign_key_create_with_valid_emptystring
(
self
):
"""
The emptystring should be interpreted as null in the context
of relationships.
"""
data
=
{
'id'
:
4
,
'name'
:
'source-4'
,
'target'
:
''
}
expected_data
=
{
'id'
:
4
,
'name'
:
'source-4'
,
'target'
:
None
}
serializer
=
NullableForeignKeySourceSerializer
(
data
=
data
)
self
.
assertTrue
(
serializer
.
is_valid
())
obj
=
serializer
.
save
()
self
.
assertEqual
(
serializer
.
data
,
expected_data
)
self
.
assertEqual
(
obj
.
name
,
'source-4'
)
# Ensure source 4 is created, and everything else is as expected
queryset
=
NullableForeignKeySource
.
objects
.
all
()
serializer
=
NullableForeignKeySourceSerializer
(
queryset
,
many
=
True
)
expected
=
[
{
'id'
:
1
,
'name'
:
'source-1'
,
'target'
:
1
},
{
'id'
:
2
,
'name'
:
'source-2'
,
'target'
:
1
},
{
'id'
:
3
,
'name'
:
'source-3'
,
'target'
:
None
},
{
'id'
:
4
,
'name'
:
'source-4'
,
'target'
:
None
}
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
def
test_foreign_key_update_with_valid_null
(
self
):
data
=
{
'id'
:
1
,
'name'
:
'source-1'
,
'target'
:
None
}
instance
=
NullableForeignKeySource
.
objects
.
get
(
pk
=
1
)
serializer
=
NullableForeignKeySourceSerializer
(
instance
,
data
=
data
)
self
.
assertTrue
(
serializer
.
is_valid
())
self
.
assertEqual
(
serializer
.
data
,
data
)
serializer
.
save
()
# Ensure source 1 is updated, and everything else is as expected
queryset
=
NullableForeignKeySource
.
objects
.
all
()
serializer
=
NullableForeignKeySourceSerializer
(
queryset
,
many
=
True
)
expected
=
[
{
'id'
:
1
,
'name'
:
'source-1'
,
'target'
:
None
},
{
'id'
:
2
,
'name'
:
'source-2'
,
'target'
:
1
},
{
'id'
:
3
,
'name'
:
'source-3'
,
'target'
:
None
}
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
def
test_foreign_key_update_with_valid_emptystring
(
self
):
"""
The emptystring should be interpreted as null in the context
of relationships.
"""
data
=
{
'id'
:
1
,
'name'
:
'source-1'
,
'target'
:
''
}
expected_data
=
{
'id'
:
1
,
'name'
:
'source-1'
,
'target'
:
None
}
instance
=
NullableForeignKeySource
.
objects
.
get
(
pk
=
1
)
serializer
=
NullableForeignKeySourceSerializer
(
instance
,
data
=
data
)
self
.
assertTrue
(
serializer
.
is_valid
())
self
.
assertEqual
(
serializer
.
data
,
expected_data
)
serializer
.
save
()
# Ensure source 1 is updated, and everything else is as expected
queryset
=
NullableForeignKeySource
.
objects
.
all
()
serializer
=
NullableForeignKeySourceSerializer
(
queryset
,
many
=
True
)
expected
=
[
{
'id'
:
1
,
'name'
:
'source-1'
,
'target'
:
None
},
{
'id'
:
2
,
'name'
:
'source-2'
,
'target'
:
1
},
{
'id'
:
3
,
'name'
:
'source-3'
,
'target'
:
None
}
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
# reverse foreign keys MUST be read_only
# In the general case they do not provide .remove() or .clear()
# and cannot be arbitrarily set.
# def test_reverse_foreign_key_update(self):
# data = {'id': 1, 'name': 'target-1', 'sources': [1]}
# instance = ForeignKeyTarget.objects.get(pk=1)
# serializer = ForeignKeyTargetSerializer(instance, data=data)
# self.assertTrue(serializer.is_valid())
# self.assertEqual(serializer.data, data)
# serializer.save()
# # Ensure target 1 is updated, and everything else is as expected
# queryset = ForeignKeyTarget.objects.all()
# serializer = ForeignKeyTargetSerializer(queryset, many=True)
# expected = [
# {'id': 1, 'name': 'target-1', 'sources': [1]},
# {'id': 2, 'name': 'target-2', 'sources': []},
# ]
# self.assertEqual(serializer.data, expected)
class
PKNullableOneToOneTests
(
TestCase
):
def
setUp
(
self
):
target
=
OneToOneTarget
(
name
=
'target-1'
)
target
.
save
()
new_target
=
OneToOneTarget
(
name
=
'target-2'
)
new_target
.
save
()
source
=
NullableOneToOneSource
(
name
=
'source-1'
,
target
=
new_target
)
source
.
save
()
def
test_reverse_foreign_key_retrieve_with_null
(
self
):
queryset
=
OneToOneTarget
.
objects
.
all
()
serializer
=
NullableOneToOneTargetSerializer
(
queryset
,
many
=
True
)
expected
=
[
{
'id'
:
1
,
'name'
:
'target-1'
,
'nullable_source'
:
None
},
{
'id'
:
2
,
'name'
:
'target-2'
,
'nullable_source'
:
1
},
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
# The below models and tests ensure that serializer fields corresponding
# to a ManyToManyField field with a user-specified ``through`` model are
# set to read only
class
ManyToManyThroughTarget
(
models
.
Model
):
name
=
models
.
CharField
(
max_length
=
100
)
class
ManyToManyThrough
(
models
.
Model
):
source
=
models
.
ForeignKey
(
'ManyToManyThroughSource'
)
target
=
models
.
ForeignKey
(
ManyToManyThroughTarget
)
class
ManyToManyThroughSource
(
models
.
Model
):
name
=
models
.
CharField
(
max_length
=
100
)
targets
=
models
.
ManyToManyField
(
ManyToManyThroughTarget
,
related_name
=
'sources'
,
through
=
'ManyToManyThrough'
)
class
ManyToManyThroughTargetSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
ManyToManyThroughTarget
fields
=
(
'id'
,
'name'
,
'sources'
)
class
ManyToManyThroughSourceSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
ManyToManyThroughSource
fields
=
(
'id'
,
'name'
,
'targets'
)
class
PKManyToManyThroughTests
(
TestCase
):
def
setUp
(
self
):
self
.
source
=
ManyToManyThroughSource
.
objects
.
create
(
name
=
'through-source-1'
)
self
.
target
=
ManyToManyThroughTarget
.
objects
.
create
(
name
=
'through-target-1'
)
def
test_many_to_many_create
(
self
):
data
=
{
'id'
:
2
,
'name'
:
'source-2'
,
'targets'
:
[
self
.
target
.
pk
]}
serializer
=
ManyToManyThroughSourceSerializer
(
data
=
data
)
self
.
assertTrue
(
serializer
.
fields
[
'targets'
]
.
read_only
)
self
.
assertTrue
(
serializer
.
is_valid
())
obj
=
serializer
.
save
()
self
.
assertEqual
(
obj
.
name
,
'source-2'
)
self
.
assertEqual
(
obj
.
targets
.
count
(),
0
)
def
test_many_to_many_reverse_create
(
self
):
data
=
{
'id'
:
2
,
'name'
:
'target-2'
,
'sources'
:
[
self
.
source
.
pk
]}
serializer
=
ManyToManyThroughTargetSerializer
(
data
=
data
)
self
.
assertTrue
(
serializer
.
fields
[
'sources'
]
.
read_only
)
self
.
assertTrue
(
serializer
.
is_valid
())
serializer
.
save
()
obj
=
serializer
.
save
()
self
.
assertEqual
(
obj
.
name
,
'target-2'
)
self
.
assertEqual
(
obj
.
sources
.
count
(),
0
)
# Regression tests for #694 (`source` attribute on related fields)
class
PrimaryKeyRelatedFieldSourceTests
(
TestCase
):
def
test_related_manager_source
(
self
):
"""
Relational fields should be able to use manager-returning methods as their source.
"""
BlogPost
.
objects
.
create
(
title
=
'blah'
)
field
=
serializers
.
PrimaryKeyRelatedField
(
many
=
True
,
source
=
'get_blogposts_manager'
)
class
ClassWithManagerMethod
(
object
):
def
get_blogposts_manager
(
self
):
return
BlogPost
.
objects
obj
=
ClassWithManagerMethod
()
value
=
field
.
field_to_native
(
obj
,
'field_name'
)
self
.
assertEqual
(
value
,
[
1
])
def
test_related_queryset_source
(
self
):
"""
Relational fields should be able to use queryset-returning methods as their source.
"""
BlogPost
.
objects
.
create
(
title
=
'blah'
)
field
=
serializers
.
PrimaryKeyRelatedField
(
many
=
True
,
source
=
'get_blogposts_queryset'
)
class
ClassWithQuerysetMethod
(
object
):
def
get_blogposts_queryset
(
self
):
return
BlogPost
.
objects
.
all
()
obj
=
ClassWithQuerysetMethod
()
value
=
field
.
field_to_native
(
obj
,
'field_name'
)
self
.
assertEqual
(
value
,
[
1
])
def
test_dotted_source
(
self
):
"""
Source argument should support dotted.source notation.
"""
BlogPost
.
objects
.
create
(
title
=
'blah'
)
field
=
serializers
.
PrimaryKeyRelatedField
(
many
=
True
,
source
=
'a.b.c'
)
class
ClassWithQuerysetMethod
(
object
):
a
=
{
'b'
:
{
'c'
:
BlogPost
.
objects
.
all
()
}
}
obj
=
ClassWithQuerysetMethod
()
value
=
field
.
field_to_native
(
obj
,
'field_name'
)
self
.
assertEqual
(
value
,
[
1
])
#
from __future__ import unicode_literals
#
from django.db import models
#
from django.test import TestCase
#
from django.utils import six
#
from rest_framework import serializers
#
from tests.models import (
#
BlogPost, ManyToManyTarget, ManyToManySource, ForeignKeyTarget, ForeignKeySource,
#
NullableForeignKeySource, OneToOneTarget, NullableOneToOneSource,
#
)
#
#
ManyToMany
#
class ManyToManyTargetSerializer(serializers.ModelSerializer):
#
class Meta:
#
model = ManyToManyTarget
#
fields = ('id', 'name', 'sources')
#
class ManyToManySourceSerializer(serializers.ModelSerializer):
#
class Meta:
#
model = ManyToManySource
#
fields = ('id', 'name', 'targets')
#
#
ForeignKey
#
class ForeignKeyTargetSerializer(serializers.ModelSerializer):
#
class Meta:
#
model = ForeignKeyTarget
#
fields = ('id', 'name', 'sources')
#
class ForeignKeySourceSerializer(serializers.ModelSerializer):
#
class Meta:
#
model = ForeignKeySource
#
fields = ('id', 'name', 'target')
#
#
Nullable ForeignKey
#
class NullableForeignKeySourceSerializer(serializers.ModelSerializer):
#
class Meta:
#
model = NullableForeignKeySource
#
fields = ('id', 'name', 'target')
#
#
Nullable OneToOne
#
class NullableOneToOneTargetSerializer(serializers.ModelSerializer):
#
class Meta:
#
model = OneToOneTarget
#
fields = ('id', 'name', 'nullable_source')
#
#
TODO: Add test that .data cannot be accessed prior to .is_valid
#
class PKManyToManyTests(TestCase):
#
def setUp(self):
#
for idx in range(1, 4):
#
target = ManyToManyTarget(name='target-%d' % idx)
#
target.save()
#
source = ManyToManySource(name='source-%d' % idx)
#
source.save()
#
for target in ManyToManyTarget.objects.all():
#
source.targets.add(target)
#
def test_many_to_many_retrieve(self):
#
queryset = ManyToManySource.objects.all()
#
serializer = ManyToManySourceSerializer(queryset, many=True)
#
expected = [
#
{'id': 1, 'name': 'source-1', 'targets': [1]},
#
{'id': 2, 'name': 'source-2', 'targets': [1, 2]},
#
{'id': 3, 'name': 'source-3', 'targets': [1, 2, 3]}
#
]
#
self.assertEqual(serializer.data, expected)
#
def test_reverse_many_to_many_retrieve(self):
#
queryset = ManyToManyTarget.objects.all()
#
serializer = ManyToManyTargetSerializer(queryset, many=True)
#
expected = [
#
{'id': 1, 'name': 'target-1', 'sources': [1, 2, 3]},
#
{'id': 2, 'name': 'target-2', 'sources': [2, 3]},
#
{'id': 3, 'name': 'target-3', 'sources': [3]}
#
]
#
self.assertEqual(serializer.data, expected)
#
def test_many_to_many_update(self):
#
data = {'id': 1, 'name': 'source-1', 'targets': [1, 2, 3]}
#
instance = ManyToManySource.objects.get(pk=1)
#
serializer = ManyToManySourceSerializer(instance, data=data)
#
self.assertTrue(serializer.is_valid())
#
serializer.save()
#
self.assertEqual(serializer.data, data)
#
# Ensure source 1 is updated, and everything else is as expected
#
queryset = ManyToManySource.objects.all()
#
serializer = ManyToManySourceSerializer(queryset, many=True)
#
expected = [
#
{'id': 1, 'name': 'source-1', 'targets': [1, 2, 3]},
#
{'id': 2, 'name': 'source-2', 'targets': [1, 2]},
#
{'id': 3, 'name': 'source-3', 'targets': [1, 2, 3]}
#
]
#
self.assertEqual(serializer.data, expected)
#
def test_reverse_many_to_many_update(self):
#
data = {'id': 1, 'name': 'target-1', 'sources': [1]}
#
instance = ManyToManyTarget.objects.get(pk=1)
#
serializer = ManyToManyTargetSerializer(instance, data=data)
#
self.assertTrue(serializer.is_valid())
#
serializer.save()
#
self.assertEqual(serializer.data, data)
#
# Ensure target 1 is updated, and everything else is as expected
#
queryset = ManyToManyTarget.objects.all()
#
serializer = ManyToManyTargetSerializer(queryset, many=True)
#
expected = [
#
{'id': 1, 'name': 'target-1', 'sources': [1]},
#
{'id': 2, 'name': 'target-2', 'sources': [2, 3]},
#
{'id': 3, 'name': 'target-3', 'sources': [3]}
#
]
#
self.assertEqual(serializer.data, expected)
#
def test_many_to_many_create(self):
#
data = {'id': 4, 'name': 'source-4', 'targets': [1, 3]}
#
serializer = ManyToManySourceSerializer(data=data)
#
self.assertTrue(serializer.is_valid())
#
obj = serializer.save()
#
self.assertEqual(serializer.data, data)
#
self.assertEqual(obj.name, 'source-4')
#
# Ensure source 4 is added, and everything else is as expected
#
queryset = ManyToManySource.objects.all()
#
serializer = ManyToManySourceSerializer(queryset, many=True)
#
self.assertFalse(serializer.fields['targets'].read_only)
#
expected = [
#
{'id': 1, 'name': 'source-1', 'targets': [1]},
#
{'id': 2, 'name': 'source-2', 'targets': [1, 2]},
#
{'id': 3, 'name': 'source-3', 'targets': [1, 2, 3]},
#
{'id': 4, 'name': 'source-4', 'targets': [1, 3]},
#
]
#
self.assertEqual(serializer.data, expected)
#
def test_reverse_many_to_many_create(self):
#
data = {'id': 4, 'name': 'target-4', 'sources': [1, 3]}
#
serializer = ManyToManyTargetSerializer(data=data)
#
self.assertFalse(serializer.fields['sources'].read_only)
#
self.assertTrue(serializer.is_valid())
#
obj = serializer.save()
#
self.assertEqual(serializer.data, data)
#
self.assertEqual(obj.name, 'target-4')
#
# Ensure target 4 is added, and everything else is as expected
#
queryset = ManyToManyTarget.objects.all()
#
serializer = ManyToManyTargetSerializer(queryset, many=True)
#
expected = [
#
{'id': 1, 'name': 'target-1', 'sources': [1, 2, 3]},
#
{'id': 2, 'name': 'target-2', 'sources': [2, 3]},
#
{'id': 3, 'name': 'target-3', 'sources': [3]},
#
{'id': 4, 'name': 'target-4', 'sources': [1, 3]}
#
]
#
self.assertEqual(serializer.data, expected)
#
class PKForeignKeyTests(TestCase):
#
def setUp(self):
#
target = ForeignKeyTarget(name='target-1')
#
target.save()
#
new_target = ForeignKeyTarget(name='target-2')
#
new_target.save()
#
for idx in range(1, 4):
#
source = ForeignKeySource(name='source-%d' % idx, target=target)
#
source.save()
#
def test_foreign_key_retrieve(self):
#
queryset = ForeignKeySource.objects.all()
#
serializer = ForeignKeySourceSerializer(queryset, many=True)
#
expected = [
#
{'id': 1, 'name': 'source-1', 'target': 1},
#
{'id': 2, 'name': 'source-2', 'target': 1},
#
{'id': 3, 'name': 'source-3', 'target': 1}
#
]
#
self.assertEqual(serializer.data, expected)
#
def test_reverse_foreign_key_retrieve(self):
#
queryset = ForeignKeyTarget.objects.all()
#
serializer = ForeignKeyTargetSerializer(queryset, many=True)
#
expected = [
#
{'id': 1, 'name': 'target-1', 'sources': [1, 2, 3]},
#
{'id': 2, 'name': 'target-2', 'sources': []},
#
]
#
self.assertEqual(serializer.data, expected)
#
def test_foreign_key_update(self):
#
data = {'id': 1, 'name': 'source-1', 'target': 2}
#
instance = ForeignKeySource.objects.get(pk=1)
#
serializer = ForeignKeySourceSerializer(instance, data=data)
#
self.assertTrue(serializer.is_valid())
#
self.assertEqual(serializer.data, data)
#
serializer.save()
#
# Ensure source 1 is updated, and everything else is as expected
#
queryset = ForeignKeySource.objects.all()
#
serializer = ForeignKeySourceSerializer(queryset, many=True)
#
expected = [
#
{'id': 1, 'name': 'source-1', 'target': 2},
#
{'id': 2, 'name': 'source-2', 'target': 1},
#
{'id': 3, 'name': 'source-3', 'target': 1}
#
]
#
self.assertEqual(serializer.data, expected)
#
def test_foreign_key_update_incorrect_type(self):
#
data = {'id': 1, 'name': 'source-1', 'target': 'foo'}
#
instance = ForeignKeySource.objects.get(pk=1)
#
serializer = ForeignKeySourceSerializer(instance, data=data)
#
self.assertFalse(serializer.is_valid())
#
self.assertEqual(serializer.errors, {'target': ['Incorrect type. Expected pk value, received %s.' % six.text_type.__name__]})
#
def test_reverse_foreign_key_update(self):
#
data = {'id': 2, 'name': 'target-2', 'sources': [1, 3]}
#
instance = ForeignKeyTarget.objects.get(pk=2)
#
serializer = ForeignKeyTargetSerializer(instance, data=data)
#
self.assertTrue(serializer.is_valid())
#
# We shouldn't have saved anything to the db yet since save
#
# hasn't been called.
#
queryset = ForeignKeyTarget.objects.all()
#
new_serializer = ForeignKeyTargetSerializer(queryset, many=True)
#
expected = [
#
{'id': 1, 'name': 'target-1', 'sources': [1, 2, 3]},
#
{'id': 2, 'name': 'target-2', 'sources': []},
#
]
#
self.assertEqual(new_serializer.data, expected)
#
serializer.save()
#
self.assertEqual(serializer.data, data)
#
# Ensure target 2 is update, and everything else is as expected
#
queryset = ForeignKeyTarget.objects.all()
#
serializer = ForeignKeyTargetSerializer(queryset, many=True)
#
expected = [
#
{'id': 1, 'name': 'target-1', 'sources': [2]},
#
{'id': 2, 'name': 'target-2', 'sources': [1, 3]},
#
]
#
self.assertEqual(serializer.data, expected)
#
def test_foreign_key_create(self):
#
data = {'id': 4, 'name': 'source-4', 'target': 2}
#
serializer = ForeignKeySourceSerializer(data=data)
#
self.assertTrue(serializer.is_valid())
#
obj = serializer.save()
#
self.assertEqual(serializer.data, data)
#
self.assertEqual(obj.name, 'source-4')
#
# Ensure source 4 is added, and everything else is as expected
#
queryset = ForeignKeySource.objects.all()
#
serializer = ForeignKeySourceSerializer(queryset, many=True)
#
expected = [
#
{'id': 1, 'name': 'source-1', 'target': 1},
#
{'id': 2, 'name': 'source-2', 'target': 1},
#
{'id': 3, 'name': 'source-3', 'target': 1},
#
{'id': 4, 'name': 'source-4', 'target': 2},
#
]
#
self.assertEqual(serializer.data, expected)
#
def test_reverse_foreign_key_create(self):
#
data = {'id': 3, 'name': 'target-3', 'sources': [1, 3]}
#
serializer = ForeignKeyTargetSerializer(data=data)
#
self.assertTrue(serializer.is_valid())
#
obj = serializer.save()
#
self.assertEqual(serializer.data, data)
#
self.assertEqual(obj.name, 'target-3')
#
# Ensure target 3 is added, and everything else is as expected
#
queryset = ForeignKeyTarget.objects.all()
#
serializer = ForeignKeyTargetSerializer(queryset, many=True)
#
expected = [
#
{'id': 1, 'name': 'target-1', 'sources': [2]},
#
{'id': 2, 'name': 'target-2', 'sources': []},
#
{'id': 3, 'name': 'target-3', 'sources': [1, 3]},
#
]
#
self.assertEqual(serializer.data, expected)
#
def test_foreign_key_update_with_invalid_null(self):
#
data = {'id': 1, 'name': 'source-1', 'target': None}
#
instance = ForeignKeySource.objects.get(pk=1)
#
serializer = ForeignKeySourceSerializer(instance, data=data)
#
self.assertFalse(serializer.is_valid())
#
self.assertEqual(serializer.errors, {'target': ['This field is required.']})
#
def test_foreign_key_with_empty(self):
#
"""
#
Regression test for #1072
#
https://github.com/tomchristie/django-rest-framework/issues/1072
#
"""
#
serializer = NullableForeignKeySourceSerializer()
#
self.assertEqual(serializer.data['target'], None)
#
class PKNullableForeignKeyTests(TestCase):
#
def setUp(self):
#
target = ForeignKeyTarget(name='target-1')
#
target.save()
#
for idx in range(1, 4):
#
if idx == 3:
#
target = None
#
source = NullableForeignKeySource(name='source-%d' % idx, target=target)
#
source.save()
#
def test_foreign_key_retrieve_with_null(self):
#
queryset = NullableForeignKeySource.objects.all()
#
serializer = NullableForeignKeySourceSerializer(queryset, many=True)
#
expected = [
#
{'id': 1, 'name': 'source-1', 'target': 1},
#
{'id': 2, 'name': 'source-2', 'target': 1},
#
{'id': 3, 'name': 'source-3', 'target': None},
#
]
#
self.assertEqual(serializer.data, expected)
#
def test_foreign_key_create_with_valid_null(self):
#
data = {'id': 4, 'name': 'source-4', 'target': None}
#
serializer = NullableForeignKeySourceSerializer(data=data)
#
self.assertTrue(serializer.is_valid())
#
obj = serializer.save()
#
self.assertEqual(serializer.data, data)
#
self.assertEqual(obj.name, 'source-4')
#
# Ensure source 4 is created, and everything else is as expected
#
queryset = NullableForeignKeySource.objects.all()
#
serializer = NullableForeignKeySourceSerializer(queryset, many=True)
#
expected = [
#
{'id': 1, 'name': 'source-1', 'target': 1},
#
{'id': 2, 'name': 'source-2', 'target': 1},
#
{'id': 3, 'name': 'source-3', 'target': None},
#
{'id': 4, 'name': 'source-4', 'target': None}
#
]
#
self.assertEqual(serializer.data, expected)
#
def test_foreign_key_create_with_valid_emptystring(self):
#
"""
#
The emptystring should be interpreted as null in the context
#
of relationships.
#
"""
#
data = {'id': 4, 'name': 'source-4', 'target': ''}
#
expected_data = {'id': 4, 'name': 'source-4', 'target': None}
#
serializer = NullableForeignKeySourceSerializer(data=data)
#
self.assertTrue(serializer.is_valid())
#
obj = serializer.save()
#
self.assertEqual(serializer.data, expected_data)
#
self.assertEqual(obj.name, 'source-4')
#
# Ensure source 4 is created, and everything else is as expected
#
queryset = NullableForeignKeySource.objects.all()
#
serializer = NullableForeignKeySourceSerializer(queryset, many=True)
#
expected = [
#
{'id': 1, 'name': 'source-1', 'target': 1},
#
{'id': 2, 'name': 'source-2', 'target': 1},
#
{'id': 3, 'name': 'source-3', 'target': None},
#
{'id': 4, 'name': 'source-4', 'target': None}
#
]
#
self.assertEqual(serializer.data, expected)
#
def test_foreign_key_update_with_valid_null(self):
#
data = {'id': 1, 'name': 'source-1', 'target': None}
#
instance = NullableForeignKeySource.objects.get(pk=1)
#
serializer = NullableForeignKeySourceSerializer(instance, data=data)
#
self.assertTrue(serializer.is_valid())
#
self.assertEqual(serializer.data, data)
#
serializer.save()
#
# Ensure source 1 is updated, and everything else is as expected
#
queryset = NullableForeignKeySource.objects.all()
#
serializer = NullableForeignKeySourceSerializer(queryset, many=True)
#
expected = [
#
{'id': 1, 'name': 'source-1', 'target': None},
#
{'id': 2, 'name': 'source-2', 'target': 1},
#
{'id': 3, 'name': 'source-3', 'target': None}
#
]
#
self.assertEqual(serializer.data, expected)
#
def test_foreign_key_update_with_valid_emptystring(self):
#
"""
#
The emptystring should be interpreted as null in the context
#
of relationships.
#
"""
#
data = {'id': 1, 'name': 'source-1', 'target': ''}
#
expected_data = {'id': 1, 'name': 'source-1', 'target': None}
#
instance = NullableForeignKeySource.objects.get(pk=1)
#
serializer = NullableForeignKeySourceSerializer(instance, data=data)
#
self.assertTrue(serializer.is_valid())
#
self.assertEqual(serializer.data, expected_data)
#
serializer.save()
#
# Ensure source 1 is updated, and everything else is as expected
#
queryset = NullableForeignKeySource.objects.all()
#
serializer = NullableForeignKeySourceSerializer(queryset, many=True)
#
expected = [
#
{'id': 1, 'name': 'source-1', 'target': None},
#
{'id': 2, 'name': 'source-2', 'target': 1},
#
{'id': 3, 'name': 'source-3', 'target': None}
#
]
#
self.assertEqual(serializer.data, expected)
#
# reverse foreign keys MUST be read_only
#
# In the general case they do not provide .remove() or .clear()
#
# and cannot be arbitrarily set.
#
# def test_reverse_foreign_key_update(self):
#
# data = {'id': 1, 'name': 'target-1', 'sources': [1]}
#
# instance = ForeignKeyTarget.objects.get(pk=1)
#
# serializer = ForeignKeyTargetSerializer(instance, data=data)
#
# self.assertTrue(serializer.is_valid())
#
# self.assertEqual(serializer.data, data)
#
# serializer.save()
#
# # Ensure target 1 is updated, and everything else is as expected
#
# queryset = ForeignKeyTarget.objects.all()
#
# serializer = ForeignKeyTargetSerializer(queryset, many=True)
#
# expected = [
#
# {'id': 1, 'name': 'target-1', 'sources': [1]},
#
# {'id': 2, 'name': 'target-2', 'sources': []},
#
# ]
#
# self.assertEqual(serializer.data, expected)
#
class PKNullableOneToOneTests(TestCase):
#
def setUp(self):
#
target = OneToOneTarget(name='target-1')
#
target.save()
#
new_target = OneToOneTarget(name='target-2')
#
new_target.save()
#
source = NullableOneToOneSource(name='source-1', target=new_target)
#
source.save()
#
def test_reverse_foreign_key_retrieve_with_null(self):
#
queryset = OneToOneTarget.objects.all()
#
serializer = NullableOneToOneTargetSerializer(queryset, many=True)
#
expected = [
#
{'id': 1, 'name': 'target-1', 'nullable_source': None},
#
{'id': 2, 'name': 'target-2', 'nullable_source': 1},
#
]
#
self.assertEqual(serializer.data, expected)
#
#
The below models and tests ensure that serializer fields corresponding
#
#
to a ManyToManyField field with a user-specified ``through`` model are
#
#
set to read only
#
class ManyToManyThroughTarget(models.Model):
#
name = models.CharField(max_length=100)
#
class ManyToManyThrough(models.Model):
#
source = models.ForeignKey('ManyToManyThroughSource')
#
target = models.ForeignKey(ManyToManyThroughTarget)
#
class ManyToManyThroughSource(models.Model):
#
name = models.CharField(max_length=100)
#
targets = models.ManyToManyField(ManyToManyThroughTarget,
#
related_name='sources',
#
through='ManyToManyThrough')
#
class ManyToManyThroughTargetSerializer(serializers.ModelSerializer):
#
class Meta:
#
model = ManyToManyThroughTarget
#
fields = ('id', 'name', 'sources')
#
class ManyToManyThroughSourceSerializer(serializers.ModelSerializer):
#
class Meta:
#
model = ManyToManyThroughSource
#
fields = ('id', 'name', 'targets')
#
class PKManyToManyThroughTests(TestCase):
#
def setUp(self):
#
self.source = ManyToManyThroughSource.objects.create(
#
name='through-source-1')
#
self.target = ManyToManyThroughTarget.objects.create(
#
name='through-target-1')
#
def test_many_to_many_create(self):
#
data = {'id': 2, 'name': 'source-2', 'targets': [self.target.pk]}
#
serializer = ManyToManyThroughSourceSerializer(data=data)
#
self.assertTrue(serializer.fields['targets'].read_only)
#
self.assertTrue(serializer.is_valid())
#
obj = serializer.save()
#
self.assertEqual(obj.name, 'source-2')
#
self.assertEqual(obj.targets.count(), 0)
#
def test_many_to_many_reverse_create(self):
#
data = {'id': 2, 'name': 'target-2', 'sources': [self.source.pk]}
#
serializer = ManyToManyThroughTargetSerializer(data=data)
#
self.assertTrue(serializer.fields['sources'].read_only)
#
self.assertTrue(serializer.is_valid())
#
serializer.save()
#
obj = serializer.save()
#
self.assertEqual(obj.name, 'target-2')
#
self.assertEqual(obj.sources.count(), 0)
#
#
Regression tests for #694 (`source` attribute on related fields)
#
class PrimaryKeyRelatedFieldSourceTests(TestCase):
#
def test_related_manager_source(self):
#
"""
#
Relational fields should be able to use manager-returning methods as their source.
#
"""
#
BlogPost.objects.create(title='blah')
#
field = serializers.PrimaryKeyRelatedField(many=True, source='get_blogposts_manager')
#
class ClassWithManagerMethod(object):
#
def get_blogposts_manager(self):
#
return BlogPost.objects
#
obj = ClassWithManagerMethod()
#
value = field.field_to_native(obj, 'field_name')
#
self.assertEqual(value, [1])
#
def test_related_queryset_source(self):
#
"""
#
Relational fields should be able to use queryset-returning methods as their source.
#
"""
#
BlogPost.objects.create(title='blah')
#
field = serializers.PrimaryKeyRelatedField(many=True, source='get_blogposts_queryset')
#
class ClassWithQuerysetMethod(object):
#
def get_blogposts_queryset(self):
#
return BlogPost.objects.all()
#
obj = ClassWithQuerysetMethod()
#
value = field.field_to_native(obj, 'field_name')
#
self.assertEqual(value, [1])
#
def test_dotted_source(self):
#
"""
#
Source argument should support dotted.source notation.
#
"""
#
BlogPost.objects.create(title='blah')
#
field = serializers.PrimaryKeyRelatedField(many=True, source='a.b.c')
#
class ClassWithQuerysetMethod(object):
#
a = {
#
'b': {
#
'c': BlogPost.objects.all()
#
}
#
}
#
obj = ClassWithQuerysetMethod()
#
value = field.field_to_native(obj, 'field_name')
#
self.assertEqual(value, [1])
tests/test_relations_slug.py
View file @
f2852811
from
django.test
import
TestCase
from
rest_framework
import
serializers
from
tests.models
import
NullableForeignKeySource
,
ForeignKeySource
,
ForeignKeyTarget
class
ForeignKeyTargetSerializer
(
serializers
.
ModelSerializer
):
sources
=
serializers
.
SlugRelatedField
(
many
=
True
,
slug_field
=
'name'
)
class
Meta
:
model
=
ForeignKeyTarget
class
ForeignKeySourceSerializer
(
serializers
.
ModelSerializer
):
target
=
serializers
.
SlugRelatedField
(
slug_field
=
'name'
)
class
Meta
:
model
=
ForeignKeySource
class
NullableForeignKeySourceSerializer
(
serializers
.
ModelSerializer
):
target
=
serializers
.
SlugRelatedField
(
slug_field
=
'name'
,
required
=
False
)
class
Meta
:
model
=
NullableForeignKeySource
# TODO: M2M Tests, FKTests (Non-nullable), One2One
class
SlugForeignKeyTests
(
TestCase
):
def
setUp
(
self
):
target
=
ForeignKeyTarget
(
name
=
'target-1'
)
target
.
save
()
new_target
=
ForeignKeyTarget
(
name
=
'target-2'
)
new_target
.
save
()
for
idx
in
range
(
1
,
4
):
source
=
ForeignKeySource
(
name
=
'source-
%
d'
%
idx
,
target
=
target
)
source
.
save
()
def
test_foreign_key_retrieve
(
self
):
queryset
=
ForeignKeySource
.
objects
.
all
()
serializer
=
ForeignKeySourceSerializer
(
queryset
,
many
=
True
)
expected
=
[
{
'id'
:
1
,
'name'
:
'source-1'
,
'target'
:
'target-1'
},
{
'id'
:
2
,
'name'
:
'source-2'
,
'target'
:
'target-1'
},
{
'id'
:
3
,
'name'
:
'source-3'
,
'target'
:
'target-1'
}
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
def
test_reverse_foreign_key_retrieve
(
self
):
queryset
=
ForeignKeyTarget
.
objects
.
all
()
serializer
=
ForeignKeyTargetSerializer
(
queryset
,
many
=
True
)
expected
=
[
{
'id'
:
1
,
'name'
:
'target-1'
,
'sources'
:
[
'source-1'
,
'source-2'
,
'source-3'
]},
{
'id'
:
2
,
'name'
:
'target-2'
,
'sources'
:
[]},
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
def
test_foreign_key_update
(
self
):
data
=
{
'id'
:
1
,
'name'
:
'source-1'
,
'target'
:
'target-2'
}
instance
=
ForeignKeySource
.
objects
.
get
(
pk
=
1
)
serializer
=
ForeignKeySourceSerializer
(
instance
,
data
=
data
)
self
.
assertTrue
(
serializer
.
is_valid
())
self
.
assertEqual
(
serializer
.
data
,
data
)
serializer
.
save
()
# Ensure source 1 is updated, and everything else is as expected
queryset
=
ForeignKeySource
.
objects
.
all
()
serializer
=
ForeignKeySourceSerializer
(
queryset
,
many
=
True
)
expected
=
[
{
'id'
:
1
,
'name'
:
'source-1'
,
'target'
:
'target-2'
},
{
'id'
:
2
,
'name'
:
'source-2'
,
'target'
:
'target-1'
},
{
'id'
:
3
,
'name'
:
'source-3'
,
'target'
:
'target-1'
}
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
def
test_foreign_key_update_incorrect_type
(
self
):
data
=
{
'id'
:
1
,
'name'
:
'source-1'
,
'target'
:
123
}
instance
=
ForeignKeySource
.
objects
.
get
(
pk
=
1
)
serializer
=
ForeignKeySourceSerializer
(
instance
,
data
=
data
)
self
.
assertFalse
(
serializer
.
is_valid
())
self
.
assertEqual
(
serializer
.
errors
,
{
'target'
:
[
'Object with name=123 does not exist.'
]})
def
test_reverse_foreign_key_update
(
self
):
data
=
{
'id'
:
2
,
'name'
:
'target-2'
,
'sources'
:
[
'source-1'
,
'source-3'
]}
instance
=
ForeignKeyTarget
.
objects
.
get
(
pk
=
2
)
serializer
=
ForeignKeyTargetSerializer
(
instance
,
data
=
data
)
self
.
assertTrue
(
serializer
.
is_valid
())
# We shouldn't have saved anything to the db yet since save
# hasn't been called.
queryset
=
ForeignKeyTarget
.
objects
.
all
()
new_serializer
=
ForeignKeyTargetSerializer
(
queryset
,
many
=
True
)
expected
=
[
{
'id'
:
1
,
'name'
:
'target-1'
,
'sources'
:
[
'source-1'
,
'source-2'
,
'source-3'
]},
{
'id'
:
2
,
'name'
:
'target-2'
,
'sources'
:
[]},
]
self
.
assertEqual
(
new_serializer
.
data
,
expected
)
serializer
.
save
()
self
.
assertEqual
(
serializer
.
data
,
data
)
# Ensure target 2 is update, and everything else is as expected
queryset
=
ForeignKeyTarget
.
objects
.
all
()
serializer
=
ForeignKeyTargetSerializer
(
queryset
,
many
=
True
)
expected
=
[
{
'id'
:
1
,
'name'
:
'target-1'
,
'sources'
:
[
'source-2'
]},
{
'id'
:
2
,
'name'
:
'target-2'
,
'sources'
:
[
'source-1'
,
'source-3'
]},
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
def
test_foreign_key_create
(
self
):
data
=
{
'id'
:
4
,
'name'
:
'source-4'
,
'target'
:
'target-2'
}
serializer
=
ForeignKeySourceSerializer
(
data
=
data
)
serializer
.
is_valid
()
self
.
assertTrue
(
serializer
.
is_valid
())
obj
=
serializer
.
save
()
self
.
assertEqual
(
serializer
.
data
,
data
)
self
.
assertEqual
(
obj
.
name
,
'source-4'
)
# Ensure source 4 is added, and everything else is as expected
queryset
=
ForeignKeySource
.
objects
.
all
()
serializer
=
ForeignKeySourceSerializer
(
queryset
,
many
=
True
)
expected
=
[
{
'id'
:
1
,
'name'
:
'source-1'
,
'target'
:
'target-1'
},
{
'id'
:
2
,
'name'
:
'source-2'
,
'target'
:
'target-1'
},
{
'id'
:
3
,
'name'
:
'source-3'
,
'target'
:
'target-1'
},
{
'id'
:
4
,
'name'
:
'source-4'
,
'target'
:
'target-2'
},
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
def
test_reverse_foreign_key_create
(
self
):
data
=
{
'id'
:
3
,
'name'
:
'target-3'
,
'sources'
:
[
'source-1'
,
'source-3'
]}
serializer
=
ForeignKeyTargetSerializer
(
data
=
data
)
self
.
assertTrue
(
serializer
.
is_valid
())
obj
=
serializer
.
save
()
self
.
assertEqual
(
serializer
.
data
,
data
)
self
.
assertEqual
(
obj
.
name
,
'target-3'
)
# Ensure target 3 is added, and everything else is as expected
queryset
=
ForeignKeyTarget
.
objects
.
all
()
serializer
=
ForeignKeyTargetSerializer
(
queryset
,
many
=
True
)
expected
=
[
{
'id'
:
1
,
'name'
:
'target-1'
,
'sources'
:
[
'source-2'
]},
{
'id'
:
2
,
'name'
:
'target-2'
,
'sources'
:
[]},
{
'id'
:
3
,
'name'
:
'target-3'
,
'sources'
:
[
'source-1'
,
'source-3'
]},
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
def
test_foreign_key_update_with_invalid_null
(
self
):
data
=
{
'id'
:
1
,
'name'
:
'source-1'
,
'target'
:
None
}
instance
=
ForeignKeySource
.
objects
.
get
(
pk
=
1
)
serializer
=
ForeignKeySourceSerializer
(
instance
,
data
=
data
)
self
.
assertFalse
(
serializer
.
is_valid
())
self
.
assertEqual
(
serializer
.
errors
,
{
'target'
:
[
'This field is required.'
]})
class
SlugNullableForeignKeyTests
(
TestCase
):
def
setUp
(
self
):
target
=
ForeignKeyTarget
(
name
=
'target-1'
)
target
.
save
()
for
idx
in
range
(
1
,
4
):
if
idx
==
3
:
target
=
None
source
=
NullableForeignKeySource
(
name
=
'source-
%
d'
%
idx
,
target
=
target
)
source
.
save
()
def
test_foreign_key_retrieve_with_null
(
self
):
queryset
=
NullableForeignKeySource
.
objects
.
all
()
serializer
=
NullableForeignKeySourceSerializer
(
queryset
,
many
=
True
)
expected
=
[
{
'id'
:
1
,
'name'
:
'source-1'
,
'target'
:
'target-1'
},
{
'id'
:
2
,
'name'
:
'source-2'
,
'target'
:
'target-1'
},
{
'id'
:
3
,
'name'
:
'source-3'
,
'target'
:
None
},
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
def
test_foreign_key_create_with_valid_null
(
self
):
data
=
{
'id'
:
4
,
'name'
:
'source-4'
,
'target'
:
None
}
serializer
=
NullableForeignKeySourceSerializer
(
data
=
data
)
self
.
assertTrue
(
serializer
.
is_valid
())
obj
=
serializer
.
save
()
self
.
assertEqual
(
serializer
.
data
,
data
)
self
.
assertEqual
(
obj
.
name
,
'source-4'
)
# Ensure source 4 is created, and everything else is as expected
queryset
=
NullableForeignKeySource
.
objects
.
all
()
serializer
=
NullableForeignKeySourceSerializer
(
queryset
,
many
=
True
)
expected
=
[
{
'id'
:
1
,
'name'
:
'source-1'
,
'target'
:
'target-1'
},
{
'id'
:
2
,
'name'
:
'source-2'
,
'target'
:
'target-1'
},
{
'id'
:
3
,
'name'
:
'source-3'
,
'target'
:
None
},
{
'id'
:
4
,
'name'
:
'source-4'
,
'target'
:
None
}
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
def
test_foreign_key_create_with_valid_emptystring
(
self
):
"""
The emptystring should be interpreted as null in the context
of relationships.
"""
data
=
{
'id'
:
4
,
'name'
:
'source-4'
,
'target'
:
''
}
expected_data
=
{
'id'
:
4
,
'name'
:
'source-4'
,
'target'
:
None
}
serializer
=
NullableForeignKeySourceSerializer
(
data
=
data
)
self
.
assertTrue
(
serializer
.
is_valid
())
obj
=
serializer
.
save
()
self
.
assertEqual
(
serializer
.
data
,
expected_data
)
self
.
assertEqual
(
obj
.
name
,
'source-4'
)
# Ensure source 4 is created, and everything else is as expected
queryset
=
NullableForeignKeySource
.
objects
.
all
()
serializer
=
NullableForeignKeySourceSerializer
(
queryset
,
many
=
True
)
expected
=
[
{
'id'
:
1
,
'name'
:
'source-1'
,
'target'
:
'target-1'
},
{
'id'
:
2
,
'name'
:
'source-2'
,
'target'
:
'target-1'
},
{
'id'
:
3
,
'name'
:
'source-3'
,
'target'
:
None
},
{
'id'
:
4
,
'name'
:
'source-4'
,
'target'
:
None
}
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
def
test_foreign_key_update_with_valid_null
(
self
):
data
=
{
'id'
:
1
,
'name'
:
'source-1'
,
'target'
:
None
}
instance
=
NullableForeignKeySource
.
objects
.
get
(
pk
=
1
)
serializer
=
NullableForeignKeySourceSerializer
(
instance
,
data
=
data
)
self
.
assertTrue
(
serializer
.
is_valid
())
self
.
assertEqual
(
serializer
.
data
,
data
)
serializer
.
save
()
# Ensure source 1 is updated, and everything else is as expected
queryset
=
NullableForeignKeySource
.
objects
.
all
()
serializer
=
NullableForeignKeySourceSerializer
(
queryset
,
many
=
True
)
expected
=
[
{
'id'
:
1
,
'name'
:
'source-1'
,
'target'
:
None
},
{
'id'
:
2
,
'name'
:
'source-2'
,
'target'
:
'target-1'
},
{
'id'
:
3
,
'name'
:
'source-3'
,
'target'
:
None
}
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
def
test_foreign_key_update_with_valid_emptystring
(
self
):
"""
The emptystring should be interpreted as null in the context
of relationships.
"""
data
=
{
'id'
:
1
,
'name'
:
'source-1'
,
'target'
:
''
}
expected_data
=
{
'id'
:
1
,
'name'
:
'source-1'
,
'target'
:
None
}
instance
=
NullableForeignKeySource
.
objects
.
get
(
pk
=
1
)
serializer
=
NullableForeignKeySourceSerializer
(
instance
,
data
=
data
)
self
.
assertTrue
(
serializer
.
is_valid
())
self
.
assertEqual
(
serializer
.
data
,
expected_data
)
serializer
.
save
()
# Ensure source 1 is updated, and everything else is as expected
queryset
=
NullableForeignKeySource
.
objects
.
all
()
serializer
=
NullableForeignKeySourceSerializer
(
queryset
,
many
=
True
)
expected
=
[
{
'id'
:
1
,
'name'
:
'source-1'
,
'target'
:
None
},
{
'id'
:
2
,
'name'
:
'source-2'
,
'target'
:
'target-1'
},
{
'id'
:
3
,
'name'
:
'source-3'
,
'target'
:
None
}
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
#
from django.test import TestCase
#
from rest_framework import serializers
#
from tests.models import NullableForeignKeySource, ForeignKeySource, ForeignKeyTarget
#
class ForeignKeyTargetSerializer(serializers.ModelSerializer):
#
sources = serializers.SlugRelatedField(many=True, slug_field='name')
#
class Meta:
#
model = ForeignKeyTarget
#
class ForeignKeySourceSerializer(serializers.ModelSerializer):
#
target = serializers.SlugRelatedField(slug_field='name')
#
class Meta:
#
model = ForeignKeySource
#
class NullableForeignKeySourceSerializer(serializers.ModelSerializer):
#
target = serializers.SlugRelatedField(slug_field='name', required=False)
#
class Meta:
#
model = NullableForeignKeySource
#
#
TODO: M2M Tests, FKTests (Non-nullable), One2One
#
class SlugForeignKeyTests(TestCase):
#
def setUp(self):
#
target = ForeignKeyTarget(name='target-1')
#
target.save()
#
new_target = ForeignKeyTarget(name='target-2')
#
new_target.save()
#
for idx in range(1, 4):
#
source = ForeignKeySource(name='source-%d' % idx, target=target)
#
source.save()
#
def test_foreign_key_retrieve(self):
#
queryset = ForeignKeySource.objects.all()
#
serializer = ForeignKeySourceSerializer(queryset, many=True)
#
expected = [
#
{'id': 1, 'name': 'source-1', 'target': 'target-1'},
#
{'id': 2, 'name': 'source-2', 'target': 'target-1'},
#
{'id': 3, 'name': 'source-3', 'target': 'target-1'}
#
]
#
self.assertEqual(serializer.data, expected)
#
def test_reverse_foreign_key_retrieve(self):
#
queryset = ForeignKeyTarget.objects.all()
#
serializer = ForeignKeyTargetSerializer(queryset, many=True)
#
expected = [
#
{'id': 1, 'name': 'target-1', 'sources': ['source-1', 'source-2', 'source-3']},
#
{'id': 2, 'name': 'target-2', 'sources': []},
#
]
#
self.assertEqual(serializer.data, expected)
#
def test_foreign_key_update(self):
#
data = {'id': 1, 'name': 'source-1', 'target': 'target-2'}
#
instance = ForeignKeySource.objects.get(pk=1)
#
serializer = ForeignKeySourceSerializer(instance, data=data)
#
self.assertTrue(serializer.is_valid())
#
self.assertEqual(serializer.data, data)
#
serializer.save()
#
# Ensure source 1 is updated, and everything else is as expected
#
queryset = ForeignKeySource.objects.all()
#
serializer = ForeignKeySourceSerializer(queryset, many=True)
#
expected = [
#
{'id': 1, 'name': 'source-1', 'target': 'target-2'},
#
{'id': 2, 'name': 'source-2', 'target': 'target-1'},
#
{'id': 3, 'name': 'source-3', 'target': 'target-1'}
#
]
#
self.assertEqual(serializer.data, expected)
#
def test_foreign_key_update_incorrect_type(self):
#
data = {'id': 1, 'name': 'source-1', 'target': 123}
#
instance = ForeignKeySource.objects.get(pk=1)
#
serializer = ForeignKeySourceSerializer(instance, data=data)
#
self.assertFalse(serializer.is_valid())
#
self.assertEqual(serializer.errors, {'target': ['Object with name=123 does not exist.']})
#
def test_reverse_foreign_key_update(self):
#
data = {'id': 2, 'name': 'target-2', 'sources': ['source-1', 'source-3']}
#
instance = ForeignKeyTarget.objects.get(pk=2)
#
serializer = ForeignKeyTargetSerializer(instance, data=data)
#
self.assertTrue(serializer.is_valid())
#
# We shouldn't have saved anything to the db yet since save
#
# hasn't been called.
#
queryset = ForeignKeyTarget.objects.all()
#
new_serializer = ForeignKeyTargetSerializer(queryset, many=True)
#
expected = [
#
{'id': 1, 'name': 'target-1', 'sources': ['source-1', 'source-2', 'source-3']},
#
{'id': 2, 'name': 'target-2', 'sources': []},
#
]
#
self.assertEqual(new_serializer.data, expected)
#
serializer.save()
#
self.assertEqual(serializer.data, data)
#
# Ensure target 2 is update, and everything else is as expected
#
queryset = ForeignKeyTarget.objects.all()
#
serializer = ForeignKeyTargetSerializer(queryset, many=True)
#
expected = [
#
{'id': 1, 'name': 'target-1', 'sources': ['source-2']},
#
{'id': 2, 'name': 'target-2', 'sources': ['source-1', 'source-3']},
#
]
#
self.assertEqual(serializer.data, expected)
#
def test_foreign_key_create(self):
#
data = {'id': 4, 'name': 'source-4', 'target': 'target-2'}
#
serializer = ForeignKeySourceSerializer(data=data)
#
serializer.is_valid()
#
self.assertTrue(serializer.is_valid())
#
obj = serializer.save()
#
self.assertEqual(serializer.data, data)
#
self.assertEqual(obj.name, 'source-4')
#
# Ensure source 4 is added, and everything else is as expected
#
queryset = ForeignKeySource.objects.all()
#
serializer = ForeignKeySourceSerializer(queryset, many=True)
#
expected = [
#
{'id': 1, 'name': 'source-1', 'target': 'target-1'},
#
{'id': 2, 'name': 'source-2', 'target': 'target-1'},
#
{'id': 3, 'name': 'source-3', 'target': 'target-1'},
#
{'id': 4, 'name': 'source-4', 'target': 'target-2'},
#
]
#
self.assertEqual(serializer.data, expected)
#
def test_reverse_foreign_key_create(self):
#
data = {'id': 3, 'name': 'target-3', 'sources': ['source-1', 'source-3']}
#
serializer = ForeignKeyTargetSerializer(data=data)
#
self.assertTrue(serializer.is_valid())
#
obj = serializer.save()
#
self.assertEqual(serializer.data, data)
#
self.assertEqual(obj.name, 'target-3')
#
# Ensure target 3 is added, and everything else is as expected
#
queryset = ForeignKeyTarget.objects.all()
#
serializer = ForeignKeyTargetSerializer(queryset, many=True)
#
expected = [
#
{'id': 1, 'name': 'target-1', 'sources': ['source-2']},
#
{'id': 2, 'name': 'target-2', 'sources': []},
#
{'id': 3, 'name': 'target-3', 'sources': ['source-1', 'source-3']},
#
]
#
self.assertEqual(serializer.data, expected)
#
def test_foreign_key_update_with_invalid_null(self):
#
data = {'id': 1, 'name': 'source-1', 'target': None}
#
instance = ForeignKeySource.objects.get(pk=1)
#
serializer = ForeignKeySourceSerializer(instance, data=data)
#
self.assertFalse(serializer.is_valid())
#
self.assertEqual(serializer.errors, {'target': ['This field is required.']})
#
class SlugNullableForeignKeyTests(TestCase):
#
def setUp(self):
#
target = ForeignKeyTarget(name='target-1')
#
target.save()
#
for idx in range(1, 4):
#
if idx == 3:
#
target = None
#
source = NullableForeignKeySource(name='source-%d' % idx, target=target)
#
source.save()
#
def test_foreign_key_retrieve_with_null(self):
#
queryset = NullableForeignKeySource.objects.all()
#
serializer = NullableForeignKeySourceSerializer(queryset, many=True)
#
expected = [
#
{'id': 1, 'name': 'source-1', 'target': 'target-1'},
#
{'id': 2, 'name': 'source-2', 'target': 'target-1'},
#
{'id': 3, 'name': 'source-3', 'target': None},
#
]
#
self.assertEqual(serializer.data, expected)
#
def test_foreign_key_create_with_valid_null(self):
#
data = {'id': 4, 'name': 'source-4', 'target': None}
#
serializer = NullableForeignKeySourceSerializer(data=data)
#
self.assertTrue(serializer.is_valid())
#
obj = serializer.save()
#
self.assertEqual(serializer.data, data)
#
self.assertEqual(obj.name, 'source-4')
#
# Ensure source 4 is created, and everything else is as expected
#
queryset = NullableForeignKeySource.objects.all()
#
serializer = NullableForeignKeySourceSerializer(queryset, many=True)
#
expected = [
#
{'id': 1, 'name': 'source-1', 'target': 'target-1'},
#
{'id': 2, 'name': 'source-2', 'target': 'target-1'},
#
{'id': 3, 'name': 'source-3', 'target': None},
#
{'id': 4, 'name': 'source-4', 'target': None}
#
]
#
self.assertEqual(serializer.data, expected)
#
def test_foreign_key_create_with_valid_emptystring(self):
#
"""
#
The emptystring should be interpreted as null in the context
#
of relationships.
#
"""
#
data = {'id': 4, 'name': 'source-4', 'target': ''}
#
expected_data = {'id': 4, 'name': 'source-4', 'target': None}
#
serializer = NullableForeignKeySourceSerializer(data=data)
#
self.assertTrue(serializer.is_valid())
#
obj = serializer.save()
#
self.assertEqual(serializer.data, expected_data)
#
self.assertEqual(obj.name, 'source-4')
#
# Ensure source 4 is created, and everything else is as expected
#
queryset = NullableForeignKeySource.objects.all()
#
serializer = NullableForeignKeySourceSerializer(queryset, many=True)
#
expected = [
#
{'id': 1, 'name': 'source-1', 'target': 'target-1'},
#
{'id': 2, 'name': 'source-2', 'target': 'target-1'},
#
{'id': 3, 'name': 'source-3', 'target': None},
#
{'id': 4, 'name': 'source-4', 'target': None}
#
]
#
self.assertEqual(serializer.data, expected)
#
def test_foreign_key_update_with_valid_null(self):
#
data = {'id': 1, 'name': 'source-1', 'target': None}
#
instance = NullableForeignKeySource.objects.get(pk=1)
#
serializer = NullableForeignKeySourceSerializer(instance, data=data)
#
self.assertTrue(serializer.is_valid())
#
self.assertEqual(serializer.data, data)
#
serializer.save()
#
# Ensure source 1 is updated, and everything else is as expected
#
queryset = NullableForeignKeySource.objects.all()
#
serializer = NullableForeignKeySourceSerializer(queryset, many=True)
#
expected = [
#
{'id': 1, 'name': 'source-1', 'target': None},
#
{'id': 2, 'name': 'source-2', 'target': 'target-1'},
#
{'id': 3, 'name': 'source-3', 'target': None}
#
]
#
self.assertEqual(serializer.data, expected)
#
def test_foreign_key_update_with_valid_emptystring(self):
#
"""
#
The emptystring should be interpreted as null in the context
#
of relationships.
#
"""
#
data = {'id': 1, 'name': 'source-1', 'target': ''}
#
expected_data = {'id': 1, 'name': 'source-1', 'target': None}
#
instance = NullableForeignKeySource.objects.get(pk=1)
#
serializer = NullableForeignKeySourceSerializer(instance, data=data)
#
self.assertTrue(serializer.is_valid())
#
self.assertEqual(serializer.data, expected_data)
#
serializer.save()
#
# Ensure source 1 is updated, and everything else is as expected
#
queryset = NullableForeignKeySource.objects.all()
#
serializer = NullableForeignKeySourceSerializer(queryset, many=True)
#
expected = [
#
{'id': 1, 'name': 'source-1', 'target': None},
#
{'id': 2, 'name': 'source-2', 'target': 'target-1'},
#
{'id': 3, 'name': 'source-3', 'target': None}
#
]
#
self.assertEqual(serializer.data, expected)
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