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
53a80044
Commit
53a80044
authored
May 18, 2013
by
Pablo Recio
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' into 725-blank-choice-dash
Conflicts: rest_framework/tests/fields.py
parents
ab8bd566
2a3056d0
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
291 additions
and
44 deletions
+291
-44
.travis.yml
+9
-8
rest_framework/fields.py
+6
-1
rest_framework/relations.py
+12
-4
rest_framework/renderers.py
+33
-9
rest_framework/runtests/settings.py
+2
-0
rest_framework/tests/fields.py
+15
-2
rest_framework/tests/generics.py
+33
-1
rest_framework/tests/relations.py
+54
-1
rest_framework/tests/relations_hyperlink.py
+71
-0
rest_framework/tests/relations_pk.py
+56
-1
rest_framework/tests/serializer.py
+0
-17
No files found.
.travis.yml
View file @
53a80044
...
@@ -7,9 +7,9 @@ python:
...
@@ -7,9 +7,9 @@ python:
-
"
3.3"
-
"
3.3"
env
:
env
:
-
DJANGO="django==1.5 --use-mirrors"
-
DJANGO="django==1.5
.1
--use-mirrors"
-
DJANGO="django==1.4.
3
--use-mirrors"
-
DJANGO="django==1.4.
5
--use-mirrors"
-
DJANGO="django==1.3.
5
--use-mirrors"
-
DJANGO="django==1.3.
7
--use-mirrors"
install
:
install
:
-
pip install $DJANGO
-
pip install $DJANGO
...
@@ -18,7 +18,7 @@ install:
...
@@ -18,7 +18,7 @@ install:
-
"
if
[[
${TRAVIS_PYTHON_VERSION::1}
!=
'3'
]];
then
pip
install
django-oauth-plus==2.0
--use-mirrors;
fi"
-
"
if
[[
${TRAVIS_PYTHON_VERSION::1}
!=
'3'
]];
then
pip
install
django-oauth-plus==2.0
--use-mirrors;
fi"
-
"
if
[[
${TRAVIS_PYTHON_VERSION::1}
!=
'3'
]];
then
pip
install
django-oauth2-provider==0.2.3
--use-mirrors;
fi"
-
"
if
[[
${TRAVIS_PYTHON_VERSION::1}
!=
'3'
]];
then
pip
install
django-oauth2-provider==0.2.3
--use-mirrors;
fi"
-
"
if
[[
${DJANGO::11}
==
'django==1.3'
]];
then
pip
install
django-filter==0.5.4
--use-mirrors;
fi"
-
"
if
[[
${DJANGO::11}
==
'django==1.3'
]];
then
pip
install
django-filter==0.5.4
--use-mirrors;
fi"
-
"
if
[[
${DJANGO::11}
!=
'django==1.3'
]];
then
pip
install
django-filter==0.6
a1
--use-mirrors;
fi"
-
"
if
[[
${DJANGO::11}
!=
'django==1.3'
]];
then
pip
install
django-filter==0.6
--use-mirrors;
fi"
-
export PYTHONPATH=.
-
export PYTHONPATH=.
script
:
script
:
...
@@ -27,10 +27,11 @@ script:
...
@@ -27,10 +27,11 @@ script:
matrix
:
matrix
:
exclude
:
exclude
:
-
python
:
"
3.2"
-
python
:
"
3.2"
env
:
DJANGO="django==1.4.
3
--use-mirrors"
env
:
DJANGO="django==1.4.
5
--use-mirrors"
-
python
:
"
3.2"
-
python
:
"
3.2"
env
:
DJANGO="django==1.3.
5
--use-mirrors"
env
:
DJANGO="django==1.3.
7
--use-mirrors"
-
python
:
"
3.3"
-
python
:
"
3.3"
env
:
DJANGO="django==1.4.
3
--use-mirrors"
env
:
DJANGO="django==1.4.
5
--use-mirrors"
-
python
:
"
3.3"
-
python
:
"
3.3"
env
:
DJANGO="django==1.3.5 --use-mirrors"
env
:
DJANGO="django==1.3.7 --use-mirrors"
rest_framework/fields.py
View file @
53a80044
...
@@ -20,6 +20,7 @@ from django import forms
...
@@ -20,6 +20,7 @@ from django import forms
from
django.forms
import
widgets
from
django.forms
import
widgets
from
django.utils.encoding
import
is_protected_type
from
django.utils.encoding
import
is_protected_type
from
django.utils.translation
import
ugettext_lazy
as
_
from
django.utils.translation
import
ugettext_lazy
as
_
from
django.utils.datastructures
import
SortedDict
from
rest_framework
import
ISO_8601
from
rest_framework
import
ISO_8601
from
rest_framework.compat
import
timezone
,
parse_date
,
parse_datetime
,
parse_time
from
rest_framework.compat
import
timezone
,
parse_date
,
parse_datetime
,
parse_time
...
@@ -171,7 +172,11 @@ class Field(object):
...
@@ -171,7 +172,11 @@ class Field(object):
elif
hasattr
(
value
,
'__iter__'
)
and
not
isinstance
(
value
,
(
dict
,
six
.
string_types
)):
elif
hasattr
(
value
,
'__iter__'
)
and
not
isinstance
(
value
,
(
dict
,
six
.
string_types
)):
return
[
self
.
to_native
(
item
)
for
item
in
value
]
return
[
self
.
to_native
(
item
)
for
item
in
value
]
elif
isinstance
(
value
,
dict
):
elif
isinstance
(
value
,
dict
):
return
dict
(
map
(
self
.
to_native
,
(
k
,
v
))
for
k
,
v
in
value
.
items
())
# Make sure we preserve field ordering, if it exists
ret
=
SortedDict
()
for
key
,
val
in
value
.
items
():
ret
[
key
]
=
self
.
to_native
(
val
)
return
ret
return
smart_text
(
value
)
return
smart_text
(
value
)
def
attributes
(
self
):
def
attributes
(
self
):
...
...
rest_framework/relations.py
View file @
53a80044
...
@@ -221,12 +221,20 @@ class PrimaryKeyRelatedField(RelatedField):
...
@@ -221,12 +221,20 @@ class PrimaryKeyRelatedField(RelatedField):
def
field_to_native
(
self
,
obj
,
field_name
):
def
field_to_native
(
self
,
obj
,
field_name
):
if
self
.
many
:
if
self
.
many
:
# To-many relationship
# To-many relationship
try
:
queryset
=
None
if
not
self
.
source
:
# Prefer obj.serializable_value for performance reasons
# Prefer obj.serializable_value for performance reasons
queryset
=
obj
.
serializable_value
(
self
.
source
or
field_name
)
try
:
except
AttributeError
:
queryset
=
obj
.
serializable_value
(
field_name
)
except
AttributeError
:
pass
if
queryset
is
None
:
# RelatedManager (reverse relationship)
# RelatedManager (reverse relationship)
queryset
=
getattr
(
obj
,
self
.
source
or
field_name
)
source
=
self
.
source
or
field_name
queryset
=
obj
for
component
in
source
.
split
(
'.'
):
queryset
=
get_component
(
queryset
,
component
)
# Forward relationship
# Forward relationship
return
[
self
.
to_native
(
item
.
pk
)
for
item
in
queryset
.
all
()]
return
[
self
.
to_native
(
item
.
pk
)
for
item
in
queryset
.
all
()]
...
...
rest_framework/renderers.py
View file @
53a80044
...
@@ -336,7 +336,7 @@ class BrowsableAPIRenderer(BaseRenderer):
...
@@ -336,7 +336,7 @@ class BrowsableAPIRenderer(BaseRenderer):
return
# Cannot use form overloading
return
# Cannot use form overloading
try
:
try
:
view
.
check_permissions
(
clone_request
(
request
,
method
)
)
view
.
check_permissions
(
request
)
except
exceptions
.
APIException
:
except
exceptions
.
APIException
:
return
False
# Doesn't have permissions
return
False
# Doesn't have permissions
return
True
return
True
...
@@ -372,6 +372,30 @@ class BrowsableAPIRenderer(BaseRenderer):
...
@@ -372,6 +372,30 @@ class BrowsableAPIRenderer(BaseRenderer):
return
fields
return
fields
def
_get_form
(
self
,
view
,
method
,
request
):
# We need to impersonate a request with the correct method,
# so that eg. any dynamic get_serializer_class methods return the
# correct form for each method.
restore
=
view
.
request
request
=
clone_request
(
request
,
method
)
view
.
request
=
request
try
:
return
self
.
get_form
(
view
,
method
,
request
)
finally
:
view
.
request
=
restore
def
_get_raw_data_form
(
self
,
view
,
method
,
request
,
media_types
):
# We need to impersonate a request with the correct method,
# so that eg. any dynamic get_serializer_class methods return the
# correct form for each method.
restore
=
view
.
request
request
=
clone_request
(
request
,
method
)
view
.
request
=
request
try
:
return
self
.
get_raw_data_form
(
view
,
method
,
request
,
media_types
)
finally
:
view
.
request
=
restore
def
get_form
(
self
,
view
,
method
,
request
):
def
get_form
(
self
,
view
,
method
,
request
):
"""
"""
Get a form, possibly bound to either the input or output data.
Get a form, possibly bound to either the input or output data.
...
@@ -465,15 +489,15 @@ class BrowsableAPIRenderer(BaseRenderer):
...
@@ -465,15 +489,15 @@ class BrowsableAPIRenderer(BaseRenderer):
renderer
=
self
.
get_default_renderer
(
view
)
renderer
=
self
.
get_default_renderer
(
view
)
content
=
self
.
get_content
(
renderer
,
data
,
accepted_media_type
,
renderer_context
)
content
=
self
.
get_content
(
renderer
,
data
,
accepted_media_type
,
renderer_context
)
put_form
=
self
.
get_form
(
view
,
'PUT'
,
request
)
put_form
=
self
.
_
get_form
(
view
,
'PUT'
,
request
)
post_form
=
self
.
get_form
(
view
,
'POST'
,
request
)
post_form
=
self
.
_
get_form
(
view
,
'POST'
,
request
)
patch_form
=
self
.
get_form
(
view
,
'PATCH'
,
request
)
patch_form
=
self
.
_
get_form
(
view
,
'PATCH'
,
request
)
delete_form
=
self
.
get_form
(
view
,
'DELETE'
,
request
)
delete_form
=
self
.
_
get_form
(
view
,
'DELETE'
,
request
)
options_form
=
self
.
get_form
(
view
,
'OPTIONS'
,
request
)
options_form
=
self
.
_
get_form
(
view
,
'OPTIONS'
,
request
)
raw_data_put_form
=
self
.
get_raw_data_form
(
view
,
'PUT'
,
request
,
media_types
)
raw_data_put_form
=
self
.
_
get_raw_data_form
(
view
,
'PUT'
,
request
,
media_types
)
raw_data_post_form
=
self
.
get_raw_data_form
(
view
,
'POST'
,
request
,
media_types
)
raw_data_post_form
=
self
.
_
get_raw_data_form
(
view
,
'POST'
,
request
,
media_types
)
raw_data_patch_form
=
self
.
get_raw_data_form
(
view
,
'PATCH'
,
request
,
media_types
)
raw_data_patch_form
=
self
.
_
get_raw_data_form
(
view
,
'PATCH'
,
request
,
media_types
)
raw_data_put_or_patch_form
=
raw_data_put_form
or
raw_data_patch_form
raw_data_put_or_patch_form
=
raw_data_put_form
or
raw_data_patch_form
name
=
self
.
get_name
(
view
)
name
=
self
.
get_name
(
view
)
...
...
rest_framework/runtests/settings.py
View file @
53a80044
...
@@ -4,6 +4,8 @@ DEBUG = True
...
@@ -4,6 +4,8 @@ DEBUG = True
TEMPLATE_DEBUG
=
DEBUG
TEMPLATE_DEBUG
=
DEBUG
DEBUG_PROPAGATE_EXCEPTIONS
=
True
DEBUG_PROPAGATE_EXCEPTIONS
=
True
ALLOWED_HOSTS
=
[
'*'
]
ADMINS
=
(
ADMINS
=
(
# ('Your Name', 'your_email@domain.com'),
# ('Your Name', 'your_email@domain.com'),
)
)
...
...
rest_framework/tests/fields.py
View file @
53a80044
...
@@ -2,13 +2,12 @@
...
@@ -2,13 +2,12 @@
General serializer field tests.
General serializer field tests.
"""
"""
from
__future__
import
unicode_literals
from
__future__
import
unicode_literals
from
django.utils.datastructures
import
SortedDict
import
datetime
import
datetime
from
decimal
import
Decimal
from
decimal
import
Decimal
from
django.db
import
models
from
django.db
import
models
from
django.test
import
TestCase
from
django.test
import
TestCase
from
django.core
import
validators
from
django.core
import
validators
from
rest_framework
import
serializers
from
rest_framework
import
serializers
from
rest_framework.serializers
import
Serializer
from
rest_framework.serializers
import
Serializer
...
@@ -63,6 +62,20 @@ class BasicFieldTests(TestCase):
...
@@ -63,6 +62,20 @@ class BasicFieldTests(TestCase):
serializer
=
CharPrimaryKeyModelSerializer
()
serializer
=
CharPrimaryKeyModelSerializer
()
self
.
assertEqual
(
serializer
.
fields
[
'id'
]
.
read_only
,
False
)
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'
])
class
DateFieldTest
(
TestCase
):
class
DateFieldTest
(
TestCase
):
"""
"""
...
...
rest_framework/tests/generics.py
View file @
53a80044
...
@@ -2,7 +2,7 @@ from __future__ import unicode_literals
...
@@ -2,7 +2,7 @@ from __future__ import unicode_literals
from
django.db
import
models
from
django.db
import
models
from
django.shortcuts
import
get_object_or_404
from
django.shortcuts
import
get_object_or_404
from
django.test
import
TestCase
from
django.test
import
TestCase
from
rest_framework
import
generics
,
serializers
,
status
from
rest_framework
import
generics
,
renderers
,
serializers
,
status
from
rest_framework.tests.utils
import
RequestFactory
from
rest_framework.tests.utils
import
RequestFactory
from
rest_framework.tests.models
import
BasicModel
,
Comment
,
SlugBasedModel
from
rest_framework.tests.models
import
BasicModel
,
Comment
,
SlugBasedModel
from
rest_framework.compat
import
six
from
rest_framework.compat
import
six
...
@@ -476,3 +476,35 @@ class TestFilterBackendAppliedToViews(TestCase):
...
@@ -476,3 +476,35 @@ class TestFilterBackendAppliedToViews(TestCase):
response
=
instance_view
(
request
,
pk
=
1
)
.
render
()
response
=
instance_view
(
request
,
pk
=
1
)
.
render
()
self
.
assertEqual
(
response
.
status_code
,
status
.
HTTP_200_OK
)
self
.
assertEqual
(
response
.
status_code
,
status
.
HTTP_200_OK
)
self
.
assertEqual
(
response
.
data
,
{
'id'
:
1
,
'text'
:
'foo'
})
self
.
assertEqual
(
response
.
data
,
{
'id'
:
1
,
'text'
:
'foo'
})
class
TwoFieldModel
(
models
.
Model
):
field_a
=
models
.
CharField
(
max_length
=
100
)
field_b
=
models
.
CharField
(
max_length
=
100
)
class
DynamicSerializerView
(
generics
.
ListCreateAPIView
):
model
=
TwoFieldModel
renderer_classes
=
(
renderers
.
BrowsableAPIRenderer
,
renderers
.
JSONRenderer
)
def
get_serializer_class
(
self
):
if
self
.
request
.
method
==
'POST'
:
class
DynamicSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
TwoFieldModel
fields
=
(
'field_b'
,)
return
DynamicSerializer
return
super
(
DynamicSerializerView
,
self
)
.
get_serializer_class
()
class
TestFilterBackendAppliedToViews
(
TestCase
):
def
test_dynamic_serializer_form_in_browsable_api
(
self
):
"""
GET requests to ListCreateAPIView should return filtered list.
"""
view
=
DynamicSerializerView
.
as_view
()
request
=
factory
.
get
(
'/'
)
response
=
view
(
request
)
.
render
()
self
.
assertContains
(
response
,
'field_b'
)
self
.
assertNotContains
(
response
,
'field_a'
)
rest_framework/tests/relations.py
View file @
53a80044
...
@@ -5,6 +5,7 @@ from __future__ import unicode_literals
...
@@ -5,6 +5,7 @@ from __future__ import unicode_literals
from
django.db
import
models
from
django.db
import
models
from
django.test
import
TestCase
from
django.test
import
TestCase
from
rest_framework
import
serializers
from
rest_framework
import
serializers
from
rest_framework.tests.models
import
BlogPost
class
NullModel
(
models
.
Model
):
class
NullModel
(
models
.
Model
):
...
@@ -33,7 +34,7 @@ class FieldTests(TestCase):
...
@@ -33,7 +34,7 @@ class FieldTests(TestCase):
self
.
assertRaises
(
serializers
.
ValidationError
,
field
.
from_native
,
[])
self
.
assertRaises
(
serializers
.
ValidationError
,
field
.
from_native
,
[])
class
TestManyRelateMixin
(
TestCase
):
class
TestManyRelate
d
Mixin
(
TestCase
):
def
test_missing_many_to_many_related_field
(
self
):
def
test_missing_many_to_many_related_field
(
self
):
'''
'''
Regression test for #632
Regression test for #632
...
@@ -45,3 +46,55 @@ class TestManyRelateMixin(TestCase):
...
@@ -45,3 +46,55 @@ class TestManyRelateMixin(TestCase):
into
=
{}
into
=
{}
field
.
field_from_native
({},
None
,
'field_name'
,
into
)
field
.
field_from_native
({},
None
,
'field_name'
,
into
)
self
.
assertEqual
(
into
[
'field_name'
],
[])
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'
])
rest_framework/tests/relations_hyperlink.py
View file @
53a80044
...
@@ -4,6 +4,7 @@ from django.test.client import RequestFactory
...
@@ -4,6 +4,7 @@ from django.test.client import RequestFactory
from
rest_framework
import
serializers
from
rest_framework
import
serializers
from
rest_framework.compat
import
patterns
,
url
from
rest_framework.compat
import
patterns
,
url
from
rest_framework.tests.models
import
(
from
rest_framework.tests.models
import
(
BlogPost
,
ManyToManyTarget
,
ManyToManySource
,
ForeignKeyTarget
,
ForeignKeySource
,
ManyToManyTarget
,
ManyToManySource
,
ForeignKeyTarget
,
ForeignKeySource
,
NullableForeignKeySource
,
OneToOneTarget
,
NullableOneToOneSource
NullableForeignKeySource
,
OneToOneTarget
,
NullableOneToOneSource
)
)
...
@@ -16,6 +17,7 @@ def dummy_view(request, pk):
...
@@ -16,6 +17,7 @@ def dummy_view(request, pk):
pass
pass
urlpatterns
=
patterns
(
''
,
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'^manytomanysource/(?P<pk>[0-9]+)/$'
,
dummy_view
,
name
=
'manytomanysource-detail'
),
url
(
r'^manytomanytarget/(?P<pk>[0-9]+)/$'
,
dummy_view
,
name
=
'manytomanytarget-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'^foreignkeysource/(?P<pk>[0-9]+)/$'
,
dummy_view
,
name
=
'foreignkeysource-detail'
),
...
@@ -451,3 +453,72 @@ class HyperlinkedNullableOneToOneTests(TestCase):
...
@@ -451,3 +453,72 @@ class HyperlinkedNullableOneToOneTests(TestCase):
{
'url'
:
'http://testserver/onetoonetarget/2/'
,
'name'
:
'target-2'
,
'nullable_source'
:
None
},
{
'url'
:
'http://testserver/onetoonetarget/2/'
,
'name'
:
'target-2'
,
'nullable_source'
:
None
},
]
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
self
.
assertEqual
(
serializer
.
data
,
expected
)
# Regression tests for #694 (`source` attribute on related fields)
class
HyperlinkedRelatedFieldSourceTests
(
TestCase
):
urls
=
'rest_framework.tests.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/'
])
rest_framework/tests/relations_pk.py
View file @
53a80044
from
__future__
import
unicode_literals
from
__future__
import
unicode_literals
from
django.test
import
TestCase
from
django.test
import
TestCase
from
rest_framework
import
serializers
from
rest_framework
import
serializers
from
rest_framework.tests.models
import
ManyToManyTarget
,
ManyToManySource
,
ForeignKeyTarget
,
ForeignKeySource
,
NullableForeignKeySource
,
OneToOneTarget
,
NullableOneToOneSource
from
rest_framework.tests.models
import
(
BlogPost
,
ManyToManyTarget
,
ManyToManySource
,
ForeignKeyTarget
,
ForeignKeySource
,
NullableForeignKeySource
,
OneToOneTarget
,
NullableOneToOneSource
,
)
from
rest_framework.compat
import
six
from
rest_framework.compat
import
six
...
@@ -421,3 +424,55 @@ class PKNullableOneToOneTests(TestCase):
...
@@ -421,3 +424,55 @@ class PKNullableOneToOneTests(TestCase):
{
'id'
:
2
,
'name'
:
'target-2'
,
'nullable_source'
:
1
},
{
'id'
:
2
,
'name'
:
'target-2'
,
'nullable_source'
:
1
},
]
]
self
.
assertEqual
(
serializer
.
data
,
expected
)
self
.
assertEqual
(
serializer
.
data
,
expected
)
# 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
])
rest_framework/tests/serializer.py
View file @
53a80044
...
@@ -872,23 +872,6 @@ class RelatedTraversalTest(TestCase):
...
@@ -872,23 +872,6 @@ class RelatedTraversalTest(TestCase):
self
.
assertEqual
(
serializer
.
data
,
expected
)
self
.
assertEqual
(
serializer
.
data
,
expected
)
def
test_queryset_nested_traversal
(
self
):
"""
Relational fields should be able to use methods as their source.
"""
BlogPost
.
objects
.
create
(
title
=
'blah'
)
class
QuerysetMethodSerializer
(
serializers
.
Serializer
):
blogposts
=
serializers
.
RelatedField
(
many
=
True
,
source
=
'get_all_blogposts'
)
class
ClassWithQuerysetMethod
(
object
):
def
get_all_blogposts
(
self
):
return
BlogPost
.
objects
obj
=
ClassWithQuerysetMethod
()
serializer
=
QuerysetMethodSerializer
(
obj
)
self
.
assertEqual
(
serializer
.
data
,
{
'blogposts'
:
[
'BlogPost object'
]})
class
SerializerMethodFieldTests
(
TestCase
):
class
SerializerMethodFieldTests
(
TestCase
):
def
setUp
(
self
):
def
setUp
(
self
):
...
...
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