mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-11-28 04:24:00 +03:00
Move page settings to property
This commit is contained in:
parent
91695fb3c6
commit
b51141cb69
|
@ -169,9 +169,6 @@ class PageNumberPagination(BasePagination):
|
||||||
http://api.example.org/accounts/?page=4
|
http://api.example.org/accounts/?page=4
|
||||||
http://api.example.org/accounts/?page=4&page_size=100
|
http://api.example.org/accounts/?page=4&page_size=100
|
||||||
"""
|
"""
|
||||||
# The default page size.
|
|
||||||
# Defaults to `None`, meaning pagination is disabled.
|
|
||||||
page_size = api_settings.PAGE_SIZE
|
|
||||||
|
|
||||||
django_paginator_class = DjangoPaginator
|
django_paginator_class = DjangoPaginator
|
||||||
|
|
||||||
|
@ -184,18 +181,33 @@ class PageNumberPagination(BasePagination):
|
||||||
page_size_query_param = None
|
page_size_query_param = None
|
||||||
page_size_query_description = _('Number of results to return per page.')
|
page_size_query_description = _('Number of results to return per page.')
|
||||||
|
|
||||||
# Set to an integer to limit the maximum page size the client may request.
|
|
||||||
# Only relevant if 'page_size_query_param' has also been set.
|
|
||||||
# Defaults to `None`, meaning page size is unlimited.
|
|
||||||
# It's recommended that you would set a limit to avoid api abuse.
|
|
||||||
max_page_size = api_settings.MAX_PAGE_SIZE
|
|
||||||
|
|
||||||
last_page_strings = ('last',)
|
last_page_strings = ('last',)
|
||||||
|
|
||||||
template = 'rest_framework/pagination/numbers.html'
|
template = 'rest_framework/pagination/numbers.html'
|
||||||
|
|
||||||
invalid_page_message = _('Invalid page.')
|
invalid_page_message = _('Invalid page.')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def page_size(self) -> int:
|
||||||
|
"""Get default page size.
|
||||||
|
|
||||||
|
Defaults to `None`, meaning pagination is disabled.
|
||||||
|
|
||||||
|
"""
|
||||||
|
return api_settings.PAGE_SIZE
|
||||||
|
|
||||||
|
@property
|
||||||
|
def max_page_size(self) -> int:
|
||||||
|
"""Limit page size.
|
||||||
|
|
||||||
|
Set to an integer to limit the maximum page size the client may request.
|
||||||
|
Only relevant if 'page_size_query_param' has also been set.
|
||||||
|
Defaults to `None`, meaning page size is unlimited.
|
||||||
|
It's recommended that you would set a limit to avoid api abuse.
|
||||||
|
|
||||||
|
"""
|
||||||
|
return api_settings.MAX_PAGE_SIZE
|
||||||
|
|
||||||
def paginate_queryset(self, queryset, request, view=None):
|
def paginate_queryset(self, queryset, request, view=None):
|
||||||
"""
|
"""
|
||||||
Paginate a queryset if required, either returning a
|
Paginate a queryset if required, either returning a
|
||||||
|
@ -379,14 +391,33 @@ class LimitOffsetPagination(BasePagination):
|
||||||
http://api.example.org/accounts/?limit=100
|
http://api.example.org/accounts/?limit=100
|
||||||
http://api.example.org/accounts/?offset=400&limit=100
|
http://api.example.org/accounts/?offset=400&limit=100
|
||||||
"""
|
"""
|
||||||
default_limit = api_settings.PAGE_SIZE
|
|
||||||
limit_query_param = 'limit'
|
limit_query_param = 'limit'
|
||||||
limit_query_description = _('Number of results to return per page.')
|
limit_query_description = _('Number of results to return per page.')
|
||||||
offset_query_param = 'offset'
|
offset_query_param = 'offset'
|
||||||
offset_query_description = _('The initial index from which to return the results.')
|
offset_query_description = _('The initial index from which to return the results.')
|
||||||
max_limit = api_settings.MAX_PAGE_SIZE
|
|
||||||
template = 'rest_framework/pagination/numbers.html'
|
template = 'rest_framework/pagination/numbers.html'
|
||||||
|
|
||||||
|
@property
|
||||||
|
def max_limit(self) -> int:
|
||||||
|
"""Limit maximum page size.
|
||||||
|
|
||||||
|
Set to an integer to limit the maximum page size the client may request.
|
||||||
|
Only relevant if 'page_size_query_param' has also been set.
|
||||||
|
Defaults to `None`, meaning page size is unlimited.
|
||||||
|
It's recommended that you would set a limit to avoid api abuse.
|
||||||
|
|
||||||
|
"""
|
||||||
|
return api_settings.MAX_PAGE_SIZE
|
||||||
|
|
||||||
|
@property
|
||||||
|
def default_limit(self) -> int:
|
||||||
|
"""Get default page size.
|
||||||
|
|
||||||
|
Defaults to `None`, meaning pagination is disabled.
|
||||||
|
|
||||||
|
"""
|
||||||
|
return api_settings.PAGE_SIZE
|
||||||
|
|
||||||
def paginate_queryset(self, queryset, request, view=None):
|
def paginate_queryset(self, queryset, request, view=None):
|
||||||
self.request = request
|
self.request = request
|
||||||
self.limit = self.get_limit(request)
|
self.limit = self.get_limit(request)
|
||||||
|
@ -590,7 +621,6 @@ class CursorPagination(BasePagination):
|
||||||
"""
|
"""
|
||||||
cursor_query_param = 'cursor'
|
cursor_query_param = 'cursor'
|
||||||
cursor_query_description = _('The pagination cursor value.')
|
cursor_query_description = _('The pagination cursor value.')
|
||||||
page_size = api_settings.PAGE_SIZE
|
|
||||||
invalid_cursor_message = _('Invalid cursor')
|
invalid_cursor_message = _('Invalid cursor')
|
||||||
ordering = '-created'
|
ordering = '-created'
|
||||||
template = 'rest_framework/pagination/previous_and_next.html'
|
template = 'rest_framework/pagination/previous_and_next.html'
|
||||||
|
@ -600,16 +630,33 @@ class CursorPagination(BasePagination):
|
||||||
page_size_query_param = None
|
page_size_query_param = None
|
||||||
page_size_query_description = _('Number of results to return per page.')
|
page_size_query_description = _('Number of results to return per page.')
|
||||||
|
|
||||||
# Set to an integer to limit the maximum page size the client may request.
|
|
||||||
# Only relevant if 'page_size_query_param' has also been set.
|
|
||||||
max_page_size = api_settings.MAX_PAGE_SIZE
|
|
||||||
|
|
||||||
# The offset in the cursor is used in situations where we have a
|
# The offset in the cursor is used in situations where we have a
|
||||||
# nearly-unique index. (Eg millisecond precision creation timestamps)
|
# nearly-unique index. (Eg millisecond precision creation timestamps)
|
||||||
# We guard against malicious users attempting to cause expensive database
|
# We guard against malicious users attempting to cause expensive database
|
||||||
# queries, by having a hard cap on the maximum possible size of the offset.
|
# queries, by having a hard cap on the maximum possible size of the offset.
|
||||||
offset_cutoff = 1000
|
offset_cutoff = 1000
|
||||||
|
|
||||||
|
@property
|
||||||
|
def page_size(self) -> int:
|
||||||
|
"""Get default page size.
|
||||||
|
|
||||||
|
Defaults to `None`, meaning pagination is disabled.
|
||||||
|
|
||||||
|
"""
|
||||||
|
return api_settings.PAGE_SIZE
|
||||||
|
|
||||||
|
@property
|
||||||
|
def max_page_size(self) -> int:
|
||||||
|
"""Limit page size.
|
||||||
|
|
||||||
|
Set to an integer to limit the maximum page size the client may request.
|
||||||
|
Only relevant if 'page_size_query_param' has also been set.
|
||||||
|
Defaults to `None`, meaning page size is unlimited.
|
||||||
|
It's recommended that you would set a limit to avoid api abuse.
|
||||||
|
|
||||||
|
"""
|
||||||
|
return api_settings.MAX_PAGE_SIZE
|
||||||
|
|
||||||
def paginate_queryset(self, queryset, request, view=None):
|
def paginate_queryset(self, queryset, request, view=None):
|
||||||
self.request = request
|
self.request = request
|
||||||
self.page_size = self.get_page_size(request)
|
self.page_size = self.get_page_size(request)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import pytest
|
import pytest
|
||||||
from django.core.paginator import Paginator as DjangoPaginator
|
from django.core.paginator import Paginator as DjangoPaginator
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.test import TestCase
|
from django.test import TestCase, override_settings
|
||||||
|
|
||||||
from rest_framework import (
|
from rest_framework import (
|
||||||
exceptions, filters, generics, pagination, serializers, status
|
exceptions, filters, generics, pagination, serializers, status
|
||||||
|
@ -135,6 +135,77 @@ class TestPaginationIntegration:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class TestPaginationSettingsIntegration:
|
||||||
|
"""
|
||||||
|
Integration tests for pagination settings.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def setup_method(self):
|
||||||
|
class PassThroughSerializer(serializers.BaseSerializer):
|
||||||
|
def to_representation(self, item):
|
||||||
|
return item
|
||||||
|
|
||||||
|
class EvenItemsOnly(filters.BaseFilterBackend):
|
||||||
|
def filter_queryset(self, request, queryset, view):
|
||||||
|
return [item for item in queryset if item % 2 == 0]
|
||||||
|
|
||||||
|
class BasicPagination(pagination.PageNumberPagination):
|
||||||
|
page_size_query_param = 'page_size'
|
||||||
|
|
||||||
|
self.view = generics.ListAPIView.as_view(
|
||||||
|
serializer_class=PassThroughSerializer,
|
||||||
|
queryset=range(1, 101),
|
||||||
|
filter_backends=[EvenItemsOnly],
|
||||||
|
pagination_class=BasicPagination
|
||||||
|
)
|
||||||
|
|
||||||
|
@override_settings(
|
||||||
|
REST_FRAMEWORK={
|
||||||
|
"MAX_PAGE_SIZE": 20,
|
||||||
|
"PAGE_SIZE": 5,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
def test_setting_page_size_over_maximum(self):
|
||||||
|
"""
|
||||||
|
When page_size parameter exceeds maximum allowable,
|
||||||
|
then it should be capped to the maximum.
|
||||||
|
"""
|
||||||
|
request = factory.get('/', {'page_size': 1000})
|
||||||
|
response = self.view(request)
|
||||||
|
assert response.status_code == status.HTTP_200_OK
|
||||||
|
assert len(response.data["results"]) == 20, response.data
|
||||||
|
assert response.data == {
|
||||||
|
'results': [
|
||||||
|
2, 4, 6, 8, 10, 12, 14, 16, 18, 20,
|
||||||
|
22, 24, 26, 28, 30, 32, 34, 36, 38, 40
|
||||||
|
],
|
||||||
|
'previous': None,
|
||||||
|
'next': 'http://testserver/?page=2&page_size=1000',
|
||||||
|
'count': 50
|
||||||
|
}
|
||||||
|
|
||||||
|
@override_settings(
|
||||||
|
REST_FRAMEWORK={
|
||||||
|
"MAX_PAGE_SIZE": 20,
|
||||||
|
"PAGE_SIZE": 5,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
def test_setting_page_size_to_zero(self):
|
||||||
|
"""
|
||||||
|
When page_size parameter is invalid it should return to the default.
|
||||||
|
"""
|
||||||
|
request = factory.get('/', {'page_size': 0})
|
||||||
|
response = self.view(request)
|
||||||
|
assert response.status_code == status.HTTP_200_OK
|
||||||
|
assert len(response.data["results"]) == 5, response.data
|
||||||
|
assert response.data == {
|
||||||
|
'results': [2, 4, 6, 8, 10],
|
||||||
|
'previous': None,
|
||||||
|
'next': 'http://testserver/?page=2&page_size=0',
|
||||||
|
'count': 50
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class TestPaginationDisabledIntegration:
|
class TestPaginationDisabledIntegration:
|
||||||
"""
|
"""
|
||||||
Integration tests for disabled pagination.
|
Integration tests for disabled pagination.
|
||||||
|
|
Loading…
Reference in New Issue
Block a user