mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-11-10 19:56:59 +03:00
Tweaks for cursor pagination and docs
This commit is contained in:
parent
f7917928c0
commit
58dfde7fcd
|
@ -51,7 +51,8 @@ You can then apply your new style to a view using the `.pagination_class` attrib
|
|||
Or apply the style globally, using the `DEFAULT_PAGINATION_CLASS` settings key. For example:
|
||||
|
||||
REST_FRAMEWORK = {
|
||||
'DEFAULT_PAGINATION_CLASS': 'apps.core.pagination.StandardResultsSetPagination'
}
|
||||
'DEFAULT_PAGINATION_CLASS': 'apps.core.pagination.StandardResultsSetPagination'
|
||||
}
|
||||
|
||||
---
|
||||
|
||||
|
@ -163,6 +164,10 @@ Cursor based pagination is more complex than other schemes. It also requires tha
|
|||
|
||||
#### Details and limitations
|
||||
|
||||
Cursor based pagination requires a specified ordering to be applied to the queryset. This will default to `'-created'`, which requires the model being paged against to have a `'created'` field.
|
||||
|
||||
|
||||
|
||||
This implementation of cursor pagination uses a smart "position plus offset" style that allows it to properly support not-strictly-unique values as the ordering.
|
||||
|
||||
It should be noted that using non-unique values the ordering does introduce the possibility of paging artifacts, where pagination consistency is no longer 100% guaranteed.
|
||||
|
@ -192,7 +197,7 @@ To set these attributes you should override the `CursorPagination` class, and th
|
|||
|
||||
* `page_size` = A numeric value indicating the page size. If set, this overrides the `DEFAULT_PAGE_SIZE` setting. Defaults to the same value as the `DEFAULT_PAGE_SIZE` settings key.
|
||||
* `cursor_query_param` = A string value indicating the name of the "cursor" query parameter. Defaults to `'cursor'`.
|
||||
* `ordering` = This should be a string, or list of strings, indicating the field against which the cursor based pagination will be applied. For example: `ordering = 'created'`. Any filters on the view which define a `get_ordering` will override this attribute. Defaults to `None`.
|
||||
* `ordering` = This should be a string, or list of strings, indicating the field against which the cursor based pagination will be applied. For example: `ordering = '-created'`. Any filters on the view which define a `get_ordering` will override this attribute. Defaults to `None`.
|
||||
* `template` = The name of a template to use when rendering pagination controls in the browsable API. May be overridden to modify the rendering style, or set to `None` to disable HTML pagination controls completely. Defaults to `"rest_framework/pagination/previous_and_next.html"`.
|
||||
|
||||
---
|
||||
|
@ -236,7 +241,8 @@ Let's modify the built-in `PageNumberPagination` style, so that instead of inclu
|
|||
|
||||
class LinkHeaderPagination(pagination.PageNumberPagination):
|
||||
def get_paginated_response(self, data):
|
||||
next_url = self.get_next_link()
previous_url = self.get_previous_link()
|
||||
next_url = self.get_next_link()
|
||||
previous_url = self.get_previous_link()
|
||||
|
||||
if next_url is not None and previous_url is not None:
|
||||
link = '<{next_url}; rel="next">, <{previous_url}; rel="prev">'
|
||||
|
|
|
@ -203,3 +203,4 @@ The next focus will be on HTML renderings of API output and will include:
|
|||
This will either be made as a single 3.2 release, or split across two separate releases, with the HTML forms and filter controls coming in 3.2, and the admin-style interface coming in a 3.3 release.
|
||||
|
||||
[custom-exception-handler]: ../api-guide/exceptions.md#custom-exception-handling
|
||||
[pagination]: ../api-guide/pagination.md
|
||||
|
|
|
@ -40,6 +40,11 @@ You can determine your currently installed version using `pip freeze`:
|
|||
|
||||
## 3.0.x series
|
||||
|
||||
### 3.1.0
|
||||
|
||||
**Date**: [5th March 2015][3.1.0-milestone].
|
||||
|
||||
For full details see the [3.1 release announcement](3.1-announcement.md).
|
||||
|
||||
### 3.0.5
|
||||
|
||||
|
|
|
@ -131,12 +131,19 @@ 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)
|
||||
offset = _positive_int(offset, cutoff=OFFSET_CUTOFF)
|
||||
|
||||
reverse = tokens.get('r', ['0'])[0]
|
||||
reverse = bool(int(reverse))
|
||||
|
@ -472,14 +479,15 @@ class LimitOffsetPagination(BasePagination):
|
|||
|
||||
|
||||
class CursorPagination(BasePagination):
|
||||
# Determine how/if True, False and None positions work - do the string
|
||||
# encodings work with Django queryset filters?
|
||||
# Consider a max offset cap.
|
||||
# Tidy up the `get_ordering` API (eg remove queryset from it)
|
||||
"""
|
||||
The cursor pagination implementation is neccessarily complex.
|
||||
For an overview of the position/offset style we use, see this post:
|
||||
http://cramer.io/2011/03/08/building-cursors-for-the-disqus-api/
|
||||
"""
|
||||
cursor_query_param = 'cursor'
|
||||
page_size = api_settings.PAGE_SIZE
|
||||
invalid_cursor_message = _('Invalid cursor')
|
||||
ordering = None
|
||||
ordering = '-created'
|
||||
template = 'rest_framework/pagination/previous_and_next.html'
|
||||
|
||||
def paginate_queryset(self, queryset, request, view=None):
|
||||
|
@ -680,12 +688,12 @@ class CursorPagination(BasePagination):
|
|||
)
|
||||
)
|
||||
else:
|
||||
# The default case is to check for an `ordering` attribute,
|
||||
# first on the view instance, and then on this pagination instance.
|
||||
ordering = getattr(view, 'ordering', getattr(self, 'ordering', None))
|
||||
# The default case is to check for an `ordering` attribute
|
||||
# on this pagination instance.
|
||||
ordering = self.ordering
|
||||
assert ordering is not None, (
|
||||
'Using cursor pagination, but no ordering attribute was declared '
|
||||
'on the view or on the pagination class.'
|
||||
'on the pagination class.'
|
||||
)
|
||||
|
||||
assert isinstance(ordering, (six.string_types, list, tuple)), (
|
||||
|
|
Loading…
Reference in New Issue
Block a user