Merge pull request #412 from minddust/custom_page_size_per_request

support for custom page size per request
This commit is contained in:
Tom Christie 2012-11-16 13:45:27 -08:00
commit 9973cf329a
6 changed files with 173 additions and 2 deletions

View File

@ -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.

View File

@ -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/

View File

@ -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

View File

@ -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):
"""

View File

@ -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'
}

View File

@ -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)