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
a1727058
Commit
a1727058
authored
Jun 23, 2015
by
Tom Christie
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #3067 from uploadcare/cursor-hooks
Cursor hooks
parents
e4b0273f
9bc0319f
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
52 additions
and
55 deletions
+52
-55
rest_framework/pagination.py
+51
-55
tests/test_pagination.py
+1
-0
No files found.
rest_framework/pagination.py
View file @
a1727058
...
...
@@ -127,50 +127,6 @@ def _get_page_links(page_numbers, current, url_func):
return
page_links
def
_decode_cursor
(
encoded
):
"""
Given a string representing an encoded cursor, return a `Cursor` instance.
"""
# The offset in the cursor is used in situations where we have a
# nearly-unique index. (Eg millisecond precision creation timestamps)
# We guard against malicious users attempting to cause expensive database
# queries, by having a hard cap on the maximum possible size of the offset.
OFFSET_CUTOFF
=
1000
try
:
querystring
=
b64decode
(
encoded
.
encode
(
'ascii'
))
.
decode
(
'ascii'
)
tokens
=
urlparse
.
parse_qs
(
querystring
,
keep_blank_values
=
True
)
offset
=
tokens
.
get
(
'o'
,
[
'0'
])[
0
]
offset
=
_positive_int
(
offset
,
cutoff
=
OFFSET_CUTOFF
)
reverse
=
tokens
.
get
(
'r'
,
[
'0'
])[
0
]
reverse
=
bool
(
int
(
reverse
))
position
=
tokens
.
get
(
'p'
,
[
None
])[
0
]
except
(
TypeError
,
ValueError
):
return
None
return
Cursor
(
offset
=
offset
,
reverse
=
reverse
,
position
=
position
)
def
_encode_cursor
(
cursor
):
"""
Given a Cursor instance, return an encoded string representation.
"""
tokens
=
{}
if
cursor
.
offset
!=
0
:
tokens
[
'o'
]
=
str
(
cursor
.
offset
)
if
cursor
.
reverse
:
tokens
[
'r'
]
=
'1'
if
cursor
.
position
is
not
None
:
tokens
[
'p'
]
=
cursor
.
position
querystring
=
urlparse
.
urlencode
(
tokens
,
doseq
=
True
)
return
b64encode
(
querystring
.
encode
(
'ascii'
))
.
decode
(
'ascii'
)
def
_reverse_ordering
(
ordering_tuple
):
"""
Given an order_by tuple such as `('-created', 'uuid')` reverse the
...
...
@@ -503,15 +459,10 @@ class CursorPagination(BasePagination):
self
.
base_url
=
request
.
build_absolute_uri
()
self
.
ordering
=
self
.
get_ordering
(
request
,
queryset
,
view
)
# Determine if we have a cursor, and if so then decode it.
encoded
=
request
.
query_params
.
get
(
self
.
cursor_query_param
)
if
encoded
is
None
:
self
.
cursor
=
None
self
.
cursor
=
self
.
decode_cursor
(
request
)
if
self
.
cursor
is
None
:
(
offset
,
reverse
,
current_position
)
=
(
0
,
False
,
None
)
else
:
self
.
cursor
=
_decode_cursor
(
encoded
)
if
self
.
cursor
is
None
:
raise
NotFound
(
self
.
invalid_cursor_message
)
(
offset
,
reverse
,
current_position
)
=
self
.
cursor
# Cursor pagination always enforces an ordering.
...
...
@@ -623,8 +574,7 @@ class CursorPagination(BasePagination):
position
=
self
.
previous_position
cursor
=
Cursor
(
offset
=
offset
,
reverse
=
False
,
position
=
position
)
encoded
=
_encode_cursor
(
cursor
)
return
replace_query_param
(
self
.
base_url
,
self
.
cursor_query_param
,
encoded
)
return
self
.
encode_cursor
(
cursor
)
def
get_previous_link
(
self
):
if
not
self
.
has_previous
:
...
...
@@ -672,8 +622,7 @@ class CursorPagination(BasePagination):
position
=
self
.
next_position
cursor
=
Cursor
(
offset
=
offset
,
reverse
=
True
,
position
=
position
)
encoded
=
_encode_cursor
(
cursor
)
return
replace_query_param
(
self
.
base_url
,
self
.
cursor_query_param
,
encoded
)
return
self
.
encode_cursor
(
cursor
)
def
get_ordering
(
self
,
request
,
queryset
,
view
):
"""
...
...
@@ -715,6 +664,53 @@ class CursorPagination(BasePagination):
return
(
ordering
,)
return
tuple
(
ordering
)
def
decode_cursor
(
self
,
request
):
"""
Given a request with a cursor, return a `Cursor` instance.
"""
# Determine if we have a cursor, and if so then decode it.
encoded
=
request
.
query_params
.
get
(
self
.
cursor_query_param
)
if
encoded
is
None
:
return
None
# The offset in the cursor is used in situations where we have a
# nearly-unique index. (Eg millisecond precision creation timestamps)
# We guard against malicious users attempting to cause expensive database
# queries, by having a hard cap on the maximum possible size of the offset.
OFFSET_CUTOFF
=
1000
try
:
querystring
=
b64decode
(
encoded
.
encode
(
'ascii'
))
.
decode
(
'ascii'
)
tokens
=
urlparse
.
parse_qs
(
querystring
,
keep_blank_values
=
True
)
offset
=
tokens
.
get
(
'o'
,
[
'0'
])[
0
]
offset
=
_positive_int
(
offset
,
cutoff
=
OFFSET_CUTOFF
)
reverse
=
tokens
.
get
(
'r'
,
[
'0'
])[
0
]
reverse
=
bool
(
int
(
reverse
))
position
=
tokens
.
get
(
'p'
,
[
None
])[
0
]
except
(
TypeError
,
ValueError
):
raise
NotFound
(
self
.
invalid_cursor_message
)
return
Cursor
(
offset
=
offset
,
reverse
=
reverse
,
position
=
position
)
def
encode_cursor
(
self
,
cursor
):
"""
Given a Cursor instance, return an url with encoded cursor.
"""
tokens
=
{}
if
cursor
.
offset
!=
0
:
tokens
[
'o'
]
=
str
(
cursor
.
offset
)
if
cursor
.
reverse
:
tokens
[
'r'
]
=
'1'
if
cursor
.
position
is
not
None
:
tokens
[
'p'
]
=
cursor
.
position
querystring
=
urlparse
.
urlencode
(
tokens
,
doseq
=
True
)
encoded
=
b64encode
(
querystring
.
encode
(
'ascii'
))
.
decode
(
'ascii'
)
return
replace_query_param
(
self
.
base_url
,
self
.
cursor_query_param
,
encoded
)
def
_get_position_from_instance
(
self
,
instance
,
ordering
):
attr
=
getattr
(
instance
,
ordering
[
0
]
.
lstrip
(
'-'
))
return
six
.
text_type
(
attr
)
...
...
tests/test_pagination.py
View file @
a1727058
...
...
@@ -186,6 +186,7 @@ class TestPageNumberPagination:
def
setup
(
self
):
class
ExamplePagination
(
pagination
.
PageNumberPagination
):
page_size
=
5
self
.
pagination
=
ExamplePagination
()
self
.
queryset
=
range
(
1
,
101
)
...
...
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