mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-08-07 13:54:47 +03:00
Merge a5208e8c12
into ad32e14360
This commit is contained in:
commit
15a212945e
|
@ -21,9 +21,11 @@ Pagination is only performed automatically if you're using the generic views or
|
||||||
|
|
||||||
The default pagination style may be set globally, using the `DEFAULT_PAGINATION_CLASS` settings key. For example, to use the built-in limit/offset pagination, you would do:
|
The default pagination style may be set globally, using the `DEFAULT_PAGINATION_CLASS` settings key. For example, to use the built-in limit/offset pagination, you would do:
|
||||||
|
|
||||||
REST_FRAMEWORK = {
|
```py
|
||||||
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination'
|
REST_FRAMEWORK = {
|
||||||
}
|
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination'
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
You can also set the pagination class on an individual view by using the `pagination_class` attribute. Typically you'll want to use the same pagination style throughout your API, although you might want to vary individual aspects of the pagination, such as default or maximum page size, on a per-view basis.
|
You can also set the pagination class on an individual view by using the `pagination_class` attribute. Typically you'll want to use the same pagination style throughout your API, although you might want to vary individual aspects of the pagination, such as default or maximum page size, on a per-view basis.
|
||||||
|
|
||||||
|
@ -31,27 +33,34 @@ You can also set the pagination class on an individual view by using the `pagina
|
||||||
|
|
||||||
If you want to modify particular aspects of the pagination style, you'll want to override one of the pagination classes, and set the attributes that you want to change.
|
If you want to modify particular aspects of the pagination style, you'll want to override one of the pagination classes, and set the attributes that you want to change.
|
||||||
|
|
||||||
class LargeResultsSetPagination(PageNumberPagination):
|
```py
|
||||||
paginate_by = 1000
|
class LargeResultsSetPagination(PageNumberPagination):
|
||||||
paginate_by_param = 'page_size'
|
paginate_by = 1000
|
||||||
max_paginate_by = 10000
|
paginate_by_param = 'page_size'
|
||||||
|
max_paginate_by = 10000
|
||||||
|
|
||||||
class StandardResultsSetPagination(PageNumberPagination):
|
class StandardResultsSetPagination(PageNumberPagination):
|
||||||
paginate_by = 100
|
paginate_by = 100
|
||||||
paginate_by_param = 'page_size'
|
paginate_by_param = 'page_size'
|
||||||
max_paginate_by = 1000
|
max_paginate_by = 1000
|
||||||
|
```
|
||||||
|
|
||||||
You can then apply your new style to a view using the `.pagination_class` attribute:
|
You can then apply your new style to a view using the `.pagination_class` attribute:
|
||||||
|
|
||||||
class BillingRecordsView(generics.ListAPIView):
|
```py
|
||||||
queryset = Billing.objects.all()
|
class BillingRecordsView(generics.ListAPIView):
|
||||||
serializer = BillingRecordsSerializer
|
queryset = Billing.objects.all()
|
||||||
pagination_class = LargeResultsSetPagination
|
serializer = BillingRecordsSerializer
|
||||||
|
pagination_class = LargeResultsSetPagination
|
||||||
|
```
|
||||||
|
|
||||||
Or apply the style globally, using the `DEFAULT_PAGINATION_CLASS` settings key. For example:
|
Or apply the style globally, using the `DEFAULT_PAGINATION_CLASS` settings key. For example:
|
||||||
|
|
||||||
REST_FRAMEWORK = {
|
```py
|
||||||
'DEFAULT_PAGINATION_CLASS': 'apps.core.pagination.StandardResultsSetPagination'
}
|
REST_FRAMEWORK = {
|
||||||
|
'DEFAULT_PAGINATION_CLASS': 'apps.core.pagination.StandardResultsSetPagination'
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -84,32 +93,49 @@ Note that the `paginate_queryset` method may set state on the pagination instanc
|
||||||
|
|
||||||
Let's modify the built-in `PageNumberPagination` style, so that instead of include the pagination links in the body of the response, we'll instead include a `Link` header, in a [similar style to the GitHub API][github-link-pagination].
|
Let's modify the built-in `PageNumberPagination` style, so that instead of include the pagination links in the body of the response, we'll instead include a `Link` header, in a [similar style to the GitHub API][github-link-pagination].
|
||||||
|
|
||||||
class LinkHeaderPagination(pagination.PageNumberPagination):
|
```py
|
||||||
def get_paginated_response(self, data):
|
from rest_framework.pagination import PageNumberPagination
|
||||||
next_url = self.get_next_link()
previous_url = self.get_previous_link()
|
from rest_framework.response import Response
|
||||||
|
|
||||||
if next_url is not None and previous_url is not None:
|
|
||||||
link = '<{next_url}; rel="next">, <{previous_url}; rel="prev">'
|
|
||||||
elif next_url is not None:
|
|
||||||
link = '<{next_url}; rel="next">'
|
|
||||||
elif previous_url is not None:
|
|
||||||
link = '<{previous_url}; rel="prev">'
|
|
||||||
else:
|
|
||||||
link = ''
|
|
||||||
|
|
||||||
link = link.format(next_url=next_url, previous_url=previous_url)
|
class LinkHeaderPagination(PageNumberPagination):
|
||||||
headers = {'Link': link} if link else {}
|
def get_paginated_response(self, data):
|
||||||
|
headers = {
|
||||||
|
'X-Page': self.page.number,
|
||||||
|
'X-Per-Page': self.page.paginator.per_page,
|
||||||
|
'X-Total': self.page.paginator.count,
|
||||||
|
'X-Total-Pages': self.page.paginator.num_pages
|
||||||
|
}
|
||||||
|
|
||||||
return Response(data, headers=headers)
|
first_url = self.get_first_link()
|
||||||
|
prev_url = self.get_previous_link()
|
||||||
|
next_url = self.get_next_link()
|
||||||
|
last_url = self.get_last_link()
|
||||||
|
|
||||||
|
link = '<{}>; rel="{}"'
|
||||||
|
links = []
|
||||||
|
|
||||||
|
if first_url: links.append(link.format(first_url, 'first'))
|
||||||
|
if prev_url: links.append(link.format(prev_url, 'prev'))
|
||||||
|
if next_url: links.append(link.format(next_url, 'next'))
|
||||||
|
if last_url: links.append(link.format(last_url, 'last'))
|
||||||
|
|
||||||
|
if links:
|
||||||
|
headers['Link'] = ", ".join(links)
|
||||||
|
|
||||||
|
return Response(data, headers=headers)
|
||||||
|
```
|
||||||
|
|
||||||
## Using your custom pagination class
|
## Using your custom pagination class
|
||||||
|
|
||||||
To have your custom pagination class be used by default, use the `DEFAULT_PAGINATION_CLASS` setting:
|
To have your custom pagination class be used by default, use the `DEFAULT_PAGINATION_CLASS` setting:
|
||||||
|
|
||||||
REST_FRAMEWORK = {
|
```py
|
||||||
'DEFAULT_PAGINATION_CLASS': 'my_project.apps.core.pagination.LinkHeaderPagination',
|
REST_FRAMEWORK = {
|
||||||
'PAGINATE_BY': 10
|
'DEFAULT_PAGINATION_CLASS': 'my_project.apps.core.pagination.LinkHeaderPagination',
|
||||||
}
|
'PAGINATE_BY': 10
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
API responses for list endpoints will now include a `Link` header, instead of including the pagination links as part of the body of the response, for example:
|
API responses for list endpoints will now include a `Link` header, instead of including the pagination links as part of the body of the response, for example:
|
||||||
|
|
||||||
|
|
|
@ -287,12 +287,11 @@ class PageNumberPagination(BasePagination):
|
||||||
|
|
||||||
return self.paginate_by
|
return self.paginate_by
|
||||||
|
|
||||||
def get_next_link(self):
|
def get_first_link(self):
|
||||||
if not self.page.has_next():
|
if not self.page.has_previous():
|
||||||
return None
|
return None
|
||||||
url = self.request.build_absolute_uri()
|
url = self.request.build_absolute_uri()
|
||||||
page_number = self.page.next_page_number()
|
return remove_query_param(url, self.page_query_param)
|
||||||
return replace_query_param(url, self.page_query_param, page_number)
|
|
||||||
|
|
||||||
def get_previous_link(self):
|
def get_previous_link(self):
|
||||||
if not self.page.has_previous():
|
if not self.page.has_previous():
|
||||||
|
@ -303,6 +302,20 @@ class PageNumberPagination(BasePagination):
|
||||||
return remove_query_param(url, self.page_query_param)
|
return remove_query_param(url, self.page_query_param)
|
||||||
return replace_query_param(url, self.page_query_param, page_number)
|
return replace_query_param(url, self.page_query_param, page_number)
|
||||||
|
|
||||||
|
def get_next_link(self):
|
||||||
|
if not self.page.has_next():
|
||||||
|
return None
|
||||||
|
url = self.request.build_absolute_uri()
|
||||||
|
page_number = self.page.next_page_number()
|
||||||
|
return replace_query_param(url, self.page_query_param, page_number)
|
||||||
|
|
||||||
|
def get_last_link(self):
|
||||||
|
if not self.page.has_next():
|
||||||
|
return None
|
||||||
|
url = self.request.build_absolute_uri()
|
||||||
|
page_number = self.page.paginator.num_pages
|
||||||
|
return replace_query_param(url, self.page_query_param, page_number)
|
||||||
|
|
||||||
def get_html_context(self):
|
def get_html_context(self):
|
||||||
base_url = self.request.build_absolute_uri()
|
base_url = self.request.build_absolute_uri()
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user