aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/api-guide/generic-views.md4
-rw-r--r--docs/api-guide/settings.md10
-rw-r--r--docs/topics/release-notes.md1
-rw-r--r--rest_framework/mixins.py13
-rw-r--r--rest_framework/settings.py4
-rw-r--r--rest_framework/tests/pagination.py143
6 files changed, 173 insertions, 2 deletions
diff --git a/docs/api-guide/generic-views.md b/docs/api-guide/generic-views.md
index 360ef1a2..3346c70a 100644
--- a/docs/api-guide/generic-views.md
+++ b/docs/api-guide/generic-views.md
@@ -147,6 +147,10 @@ Provides a `.list(request, *args, **kwargs)` method, that implements listing a q
Should be mixed in with [MultipleObjectAPIView].
+**Arguments**:
+
+* `page_size_kwarg` - Allows you to overwrite the global settings `PAGE_SIZE_KWARG` for a specific view. You can also turn it off for a specific view by setting it to `None`. Default is `page_size`.
+
## CreateModelMixin
Provides a `.create(request, *args, **kwargs)` method, that implements creating and saving a new model instance.
diff --git a/docs/api-guide/settings.md b/docs/api-guide/settings.md
index 4f87b30d..8fce9e4e 100644
--- a/docs/api-guide/settings.md
+++ b/docs/api-guide/settings.md
@@ -150,4 +150,14 @@ Default: `'accept'`
Default: `'format'`
+## PAGE_SIZE_KWARG
+
+Allows you to globally pass a page size parameter for an individual request.
+
+The name of the GET parameter of views which inherit ListModelMixin for requesting data with an individual page size.
+
+If the value if this setting is `None` the passing a page size is turned off by default.
+
+Default: `'page_size'`
+
[cite]: http://www.python.org/dev/peps/pep-0020/
diff --git a/docs/topics/release-notes.md b/docs/topics/release-notes.md
index 35e8a8b3..85c19f5b 100644
--- a/docs/topics/release-notes.md
+++ b/docs/topics/release-notes.md
@@ -7,6 +7,7 @@
## Master
* Support for `read_only_fields` on `ModelSerializer` classes.
+* Support for individual page sizes per request via `page_size` GET parameter in views which inherit ListModelMixin.
## 2.1.2
diff --git a/rest_framework/mixins.py b/rest_framework/mixins.py
index 53c4d984..0da4c2cc 100644
--- a/rest_framework/mixins.py
+++ b/rest_framework/mixins.py
@@ -7,6 +7,7 @@ which allows mixin classes to be composed in interesting ways.
from django.http import Http404
from rest_framework import status
from rest_framework.response import Response
+from rest_framework.settings import api_settings
class CreateModelMixin(object):
@@ -39,6 +40,7 @@ class ListModelMixin(object):
Should be mixed in with `MultipleObjectAPIView`.
"""
empty_error = u"Empty list and '%(class_name)s.allow_empty' is False."
+ page_size_kwarg = api_settings.PAGE_SIZE_KWARG
def list(self, request, *args, **kwargs):
queryset = self.get_queryset()
@@ -64,6 +66,17 @@ class ListModelMixin(object):
return Response(serializer.data)
+ def get_paginate_by(self, queryset):
+ if self.page_size_kwarg is not None:
+ page_size_kwarg = self.request.QUERY_PARAMS.get(self.page_size_kwarg)
+ if page_size_kwarg:
+ try:
+ page_size = int(page_size_kwarg)
+ return page_size
+ except ValueError:
+ pass
+ return super(ListModelMixin, self).get_paginate_by(queryset)
+
class RetrieveModelMixin(object):
"""
diff --git a/rest_framework/settings.py b/rest_framework/settings.py
index 4f10481d..8883b963 100644
--- a/rest_framework/settings.py
+++ b/rest_framework/settings.py
@@ -66,7 +66,9 @@ DEFAULTS = {
'URL_ACCEPT_OVERRIDE': 'accept',
'URL_FORMAT_OVERRIDE': 'format',
- 'FORMAT_SUFFIX_KWARG': 'format'
+ 'FORMAT_SUFFIX_KWARG': 'format',
+
+ 'PAGE_SIZE_KWARG': 'page_size'
}
diff --git a/rest_framework/tests/pagination.py b/rest_framework/tests/pagination.py
index 713a7255..8aae2147 100644
--- a/rest_framework/tests/pagination.py
+++ b/rest_framework/tests/pagination.py
@@ -34,6 +34,29 @@ if django_filters:
filter_backend = filters.DjangoFilterBackend
+class DefaultPageSizeKwargView(generics.ListAPIView):
+ """
+ View for testing default page_size usage
+ """
+ model = BasicModel
+
+
+class CustomPageSizeKwargView(generics.ListAPIView):
+ """
+ View for testing custom page_size usage
+ """
+ model = BasicModel
+ page_size_kwarg = 'ps'
+
+
+class NonePageSizeKwargView(generics.ListAPIView):
+ """
+ View for testing None page_size usage
+ """
+ model = BasicModel
+ page_size_kwarg = None
+
+
class IntegrationTestPagination(TestCase):
"""
Integration tests for paginated list views.
@@ -135,7 +158,7 @@ class IntegrationTestPaginationAndFiltering(TestCase):
class UnitTestPagination(TestCase):
"""
- Unit tests for pagination of primative objects.
+ Unit tests for pagination of primitive objects.
"""
def setUp(self):
@@ -156,3 +179,121 @@ class UnitTestPagination(TestCase):
self.assertEquals(serializer.data['next'], None)
self.assertEquals(serializer.data['previous'], '?page=2')
self.assertEquals(serializer.data['results'], self.objects[20:])
+
+
+class TestDefaultPageSizeKwarg(TestCase):
+ """
+ Tests for list views with default page size kwarg
+ """
+
+ def setUp(self):
+ """
+ Create 13 BasicModel instances.
+ """
+ for i in range(13):
+ BasicModel(text=i).save()
+ self.objects = BasicModel.objects
+ self.data = [
+ {'id': obj.id, 'text': obj.text}
+ for obj in self.objects.all()
+ ]
+ self.view = DefaultPageSizeKwargView.as_view()
+
+ def test_default_page_size(self):
+ """
+ Tests the default page size for this view.
+ no page size --> no limit --> no meta data
+ """
+ request = factory.get('/')
+ response = self.view(request).render()
+ self.assertEquals(response.data, self.data)
+
+ def test_default_page_size_kwarg(self):
+ """
+ If page_size_kwarg is set not set, the default page_size kwarg should limit per view requests.
+ """
+ request = factory.get('/?page_size=5')
+ response = self.view(request).render()
+ self.assertEquals(response.data['count'], 13)
+ self.assertEquals(response.data['results'], self.data[:5])
+
+
+class TestCustomPageSizeKwarg(TestCase):
+ """
+ Tests for list views with default page size kwarg
+ """
+
+ def setUp(self):
+ """
+ Create 13 BasicModel instances.
+ """
+ for i in range(13):
+ BasicModel(text=i).save()
+ self.objects = BasicModel.objects
+ self.data = [
+ {'id': obj.id, 'text': obj.text}
+ for obj in self.objects.all()
+ ]
+ self.view = CustomPageSizeKwargView.as_view()
+
+ def test_default_page_size(self):
+ """
+ Tests the default page size for this view.
+ no page size --> no limit --> no meta data
+ """
+ request = factory.get('/')
+ response = self.view(request).render()
+ self.assertEquals(response.data, self.data)
+
+ def test_disabled_default_page_size_kwarg(self):
+ """
+ If page_size_kwarg is set set, the default page_size kwarg should not work.
+ """
+ request = factory.get('/?page_size=5')
+ response = self.view(request).render()
+ self.assertEquals(response.data, self.data)
+
+ def test_custom_page_size_kwarg(self):
+ """
+ If page_size_kwarg is set set, the new kwarg should limit per view requests.
+ """
+ request = factory.get('/?ps=5')
+ response = self.view(request).render()
+ self.assertEquals(response.data['count'], 13)
+ self.assertEquals(response.data['results'], self.data[:5])
+
+
+class TestNonePageSizeKwarg(TestCase):
+ """
+ Tests for list views with default page size kwarg
+ """
+
+ def setUp(self):
+ """
+ Create 13 BasicModel instances.
+ """
+ for i in range(13):
+ BasicModel(text=i).save()
+ self.objects = BasicModel.objects
+ self.data = [
+ {'id': obj.id, 'text': obj.text}
+ for obj in self.objects.all()
+ ]
+ self.view = NonePageSizeKwargView.as_view()
+
+ def test_default_page_size(self):
+ """
+ Tests the default page size for this view.
+ no page size --> no limit --> no meta data
+ """
+ request = factory.get('/')
+ response = self.view(request).render()
+ self.assertEquals(response.data, self.data)
+
+ def test_none_page_size_kwarg(self):
+ """
+ If page_size_kwarg is set to None, custom page_size per request should be disabled.
+ """
+ request = factory.get('/?page_size=5')
+ response = self.view(request).render()
+ self.assertEquals(response.data, self.data)