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
3af5df19
Commit
3af5df19
authored
Oct 16, 2014
by
Tom Christie
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Performance for PK fields
parent
32fd82ba
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
43 additions
and
3 deletions
+43
-3
rest_framework/relations.py
+39
-3
tests/test_relations_pk.py
+4
-0
No files found.
rest_framework/relations.py
View file @
3af5df19
from
rest_framework.compat
import
smart_text
,
urlparse
from
rest_framework.fields
import
empty
,
Field
from
rest_framework.fields
import
get_attribute
,
empty
,
Field
from
rest_framework.reverse
import
reverse
from
rest_framework.utils
import
html
from
django.core.exceptions
import
ObjectDoesNotExist
,
ImproperlyConfigured
...
...
@@ -9,6 +9,11 @@ from django.utils import six
from
django.utils.translation
import
ugettext_lazy
as
_
class
PKOnlyObject
(
object
):
def
__init__
(
self
,
pk
):
self
.
pk
=
pk
class
RelatedField
(
Field
):
def
__init__
(
self
,
**
kwargs
):
self
.
queryset
=
kwargs
.
pop
(
'queryset'
,
None
)
...
...
@@ -45,6 +50,10 @@ class RelatedField(Field):
queryset
=
queryset
.
all
()
return
queryset
def
get_iterable
(
self
,
instance
,
source
):
relationship
=
get_attribute
(
instance
,
[
source
])
return
relationship
.
all
()
if
(
hasattr
(
relationship
,
'all'
))
else
relationship
@property
def
choices
(
self
):
return
dict
([
...
...
@@ -85,6 +94,31 @@ class PrimaryKeyRelatedField(RelatedField):
except
(
TypeError
,
ValueError
):
self
.
fail
(
'incorrect_type'
,
data_type
=
type
(
data
)
.
__name__
)
def
get_attribute
(
self
,
instance
):
# We customize `get_attribute` here for performance reasons.
# For relationships the instance will already have the pk of
# the related object. We return this directly instead of returning the
# object itself, which would require a database lookup.
try
:
return
PKOnlyObject
(
pk
=
instance
.
serializable_value
(
self
.
source
))
except
AttributeError
:
return
get_attribute
(
instance
,
[
self
.
source
])
def
get_iterable
(
self
,
instance
,
source
):
# For consistency with `get_attribute` we're using `serializable_value()`
# here. Typically there won't be any difference, but some custom field
# types might return a non-primative value for the pk otherwise.
#
# We could try to get smart with `values_list('pk', flat=True)`, which
# would be better in some case, but would actually end up with *more*
# queries if the developer is using `prefetch_related` across the
# relationship.
relationship
=
super
(
PrimaryKeyRelatedField
,
self
)
.
get_iterable
(
instance
,
source
)
return
[
PKOnlyObject
(
pk
=
item
.
serializable_value
(
'pk'
))
for
item
in
relationship
]
def
to_representation
(
self
,
value
):
return
value
.
pk
...
...
@@ -277,8 +311,10 @@ class ManyRelation(Field):
for
item
in
data
]
def
to_representation
(
self
,
obj
):
iterable
=
obj
.
all
()
if
(
hasattr
(
obj
,
'all'
))
else
obj
def
get_attribute
(
self
,
instance
):
return
self
.
child_relation
.
get_iterable
(
instance
,
self
.
source
)
def
to_representation
(
self
,
iterable
):
return
[
self
.
child_relation
.
to_representation
(
value
)
for
value
in
iterable
...
...
tests/test_relations_pk.py
View file @
3af5df19
...
...
@@ -68,6 +68,7 @@ class PKManyToManyTests(TestCase):
{
'id'
:
2
,
'name'
:
'source-2'
,
'targets'
:
[
1
,
2
]},
{
'id'
:
3
,
'name'
:
'source-3'
,
'targets'
:
[
1
,
2
,
3
]}
]
with
self
.
assertNumQueries
(
4
):
self
.
assertEqual
(
serializer
.
data
,
expected
)
def
test_reverse_many_to_many_retrieve
(
self
):
...
...
@@ -78,6 +79,7 @@ class PKManyToManyTests(TestCase):
{
'id'
:
2
,
'name'
:
'target-2'
,
'sources'
:
[
2
,
3
]},
{
'id'
:
3
,
'name'
:
'target-3'
,
'sources'
:
[
3
]}
]
with
self
.
assertNumQueries
(
4
):
self
.
assertEqual
(
serializer
.
data
,
expected
)
def
test_many_to_many_update
(
self
):
...
...
@@ -173,6 +175,7 @@ class PKForeignKeyTests(TestCase):
{
'id'
:
2
,
'name'
:
'source-2'
,
'target'
:
1
},
{
'id'
:
3
,
'name'
:
'source-3'
,
'target'
:
1
}
]
with
self
.
assertNumQueries
(
1
):
self
.
assertEqual
(
serializer
.
data
,
expected
)
def
test_reverse_foreign_key_retrieve
(
self
):
...
...
@@ -182,6 +185,7 @@ class PKForeignKeyTests(TestCase):
{
'id'
:
1
,
'name'
:
'target-1'
,
'sources'
:
[
1
,
2
,
3
]},
{
'id'
:
2
,
'name'
:
'target-2'
,
'sources'
:
[]},
]
with
self
.
assertNumQueries
(
3
):
self
.
assertEqual
(
serializer
.
data
,
expected
)
def
test_foreign_key_update
(
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