django-rest-framework/rest_framework/tests/pagination.py

326 lines
11 KiB
Python
Raw Normal View History

from __future__ import unicode_literals
import datetime
from decimal import Decimal
2012-10-01 18:49:19 +04:00
from django.core.paginator import Paginator
2012-09-30 20:31:28 +04:00
from django.test import TestCase
from django.test.client import RequestFactory
from django.utils import unittest
from rest_framework import generics, status, pagination, filters, serializers
from rest_framework.compat import django_filters
from rest_framework.tests.models import BasicModel, FilterableItem
2012-09-30 20:31:28 +04:00
factory = RequestFactory()
2012-10-03 12:26:15 +04:00
class RootView(generics.ListCreateAPIView):
2012-09-30 20:31:28 +04:00
"""
Example description for OPTIONS.
"""
model = BasicModel
paginate_by = 10
if django_filters:
class DecimalFilter(django_filters.FilterSet):
decimal = django_filters.NumberFilter(lookup_type='lt')
class Meta:
model = FilterableItem
fields = ['text', 'decimal', 'date']
class FilterFieldsRootView(generics.ListCreateAPIView):
model = FilterableItem
paginate_by = 10
filter_class = DecimalFilter
2012-11-09 01:46:53 +04:00
filter_backend = filters.DjangoFilterBackend
2012-11-15 17:35:34 +04:00
class DefaultPageSizeKwargView(generics.ListAPIView):
"""
View for testing default paginate_by_param usage
2012-11-15 17:35:34 +04:00
"""
model = BasicModel
class PaginateByParamView(generics.ListAPIView):
2012-11-15 17:35:34 +04:00
"""
View for testing custom paginate_by_param usage
2012-11-15 17:35:34 +04:00
"""
model = BasicModel
paginate_by_param = 'page_size'
2012-11-15 17:35:34 +04:00
2012-10-01 18:49:19 +04:00
class IntegrationTestPagination(TestCase):
"""
Integration tests for paginated list views.
"""
2012-09-30 20:31:28 +04:00
def setUp(self):
"""
Create 26 BasicModel instances.
2012-09-30 20:31:28 +04:00
"""
for char in 'abcdefghijklmnopqrstuvwxyz':
BasicModel(text=char * 3).save()
self.objects = BasicModel.objects
self.data = [
{'id': obj.id, 'text': obj.text}
for obj in self.objects.all()
]
self.view = RootView.as_view()
def test_get_paginated_root_view(self):
"""
2012-10-03 12:26:15 +04:00
GET requests to paginated ListCreateAPIView should return paginated results.
2012-09-30 20:31:28 +04:00
"""
request = factory.get('/')
response = self.view(request).render()
2013-02-28 01:15:00 +04:00
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['count'], 26)
self.assertEqual(response.data['results'], self.data[:10])
self.assertNotEqual(response.data['next'], None)
self.assertEqual(response.data['previous'], None)
2012-09-30 20:31:28 +04:00
request = factory.get(response.data['next'])
response = self.view(request).render()
2013-02-28 01:15:00 +04:00
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['count'], 26)
self.assertEqual(response.data['results'], self.data[10:20])
self.assertNotEqual(response.data['next'], None)
self.assertNotEqual(response.data['previous'], None)
2012-09-30 20:31:28 +04:00
request = factory.get(response.data['next'])
response = self.view(request).render()
2013-02-28 01:15:00 +04:00
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['count'], 26)
self.assertEqual(response.data['results'], self.data[20:])
self.assertEqual(response.data['next'], None)
self.assertNotEqual(response.data['previous'], None)
2012-10-01 18:49:19 +04:00
2012-10-11 13:32:51 +04:00
class IntegrationTestPaginationAndFiltering(TestCase):
def setUp(self):
"""
Create 50 FilterableItem instances.
"""
2012-10-11 16:19:29 +04:00
base_data = ('a', Decimal('0.25'), datetime.date(2012, 10, 8))
for i in range(26):
text = chr(i + ord(base_data[0])) * 3 # Produces string 'aaa', 'bbb', etc.
decimal = base_data[1] + i
date = base_data[2] - datetime.timedelta(days=i * 2)
FilterableItem(text=text, decimal=decimal, date=date).save()
self.objects = FilterableItem.objects
self.data = [
{'id': obj.id, 'text': obj.text, 'decimal': obj.decimal, 'date': obj.date}
for obj in self.objects.all()
]
self.view = FilterFieldsRootView.as_view()
@unittest.skipUnless(django_filters, 'django-filters not installed')
def test_get_paginated_filtered_root_view(self):
"""
GET requests to paginated filtered ListCreateAPIView should return
paginated results. The next and previous links should preserve the
filtered parameters.
"""
request = factory.get('/?decimal=15.20')
response = self.view(request).render()
2013-02-28 01:15:00 +04:00
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['count'], 15)
self.assertEqual(response.data['results'], self.data[:10])
self.assertNotEqual(response.data['next'], None)
self.assertEqual(response.data['previous'], None)
request = factory.get(response.data['next'])
response = self.view(request).render()
2013-02-28 01:15:00 +04:00
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['count'], 15)
self.assertEqual(response.data['results'], self.data[10:15])
self.assertEqual(response.data['next'], None)
self.assertNotEqual(response.data['previous'], None)
request = factory.get(response.data['previous'])
response = self.view(request).render()
2013-02-28 01:15:00 +04:00
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['count'], 15)
self.assertEqual(response.data['results'], self.data[:10])
self.assertNotEqual(response.data['next'], None)
self.assertEqual(response.data['previous'], None)
2012-10-01 18:49:19 +04:00
class PassOnContextPaginationSerializer(pagination.PaginationSerializer):
class Meta:
object_serializer_class = serializers.Serializer
2012-10-01 18:49:19 +04:00
class UnitTestPagination(TestCase):
"""
2012-11-15 17:35:34 +04:00
Unit tests for pagination of primitive objects.
2012-10-01 18:49:19 +04:00
"""
def setUp(self):
self.objects = [char * 3 for char in 'abcdefghijklmnopqrstuvwxyz']
paginator = Paginator(self.objects, 10)
self.first_page = paginator.page(1)
self.last_page = paginator.page(3)
def test_native_pagination(self):
serializer = pagination.PaginationSerializer(self.first_page)
2013-02-28 01:15:00 +04:00
self.assertEqual(serializer.data['count'], 26)
self.assertEqual(serializer.data['next'], '?page=2')
self.assertEqual(serializer.data['previous'], None)
self.assertEqual(serializer.data['results'], self.objects[:10])
2012-10-01 18:49:19 +04:00
serializer = pagination.PaginationSerializer(self.last_page)
2013-02-28 01:15:00 +04:00
self.assertEqual(serializer.data['count'], 26)
self.assertEqual(serializer.data['next'], None)
self.assertEqual(serializer.data['previous'], '?page=2')
self.assertEqual(serializer.data['results'], self.objects[20:])
2012-11-15 17:35:34 +04:00
def test_context_available_in_result(self):
"""
Ensure context gets passed through to the object serializer.
"""
2013-01-08 01:37:44 +04:00
serializer = PassOnContextPaginationSerializer(self.first_page, context={'foo': 'bar'})
serializer.data
results = serializer.fields[serializer.results_field]
2013-02-28 01:15:00 +04:00
self.assertEqual(serializer.context, results.context)
2012-11-15 17:35:34 +04:00
class TestUnpaginated(TestCase):
2012-11-15 17:35:34 +04:00
"""
Tests for list views without pagination.
2012-11-15 17:35:34 +04:00
"""
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_unpaginated(self):
2012-11-15 17:35:34 +04:00
"""
Tests the default page size for this view.
no page size --> no limit --> no meta data
"""
request = factory.get('/')
response = self.view(request)
2013-02-28 01:15:00 +04:00
self.assertEqual(response.data, self.data)
2012-11-15 17:35:34 +04:00
class TestCustomPaginateByParam(TestCase):
2012-11-15 17:35:34 +04:00
"""
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 = PaginateByParamView.as_view()
2012-11-15 17:35:34 +04:00
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()
2013-02-28 01:15:00 +04:00
self.assertEqual(response.data, self.data)
2012-11-15 17:35:34 +04:00
def test_paginate_by_param(self):
2012-11-15 17:35:34 +04:00
"""
If paginate_by_param is set, the new kwarg should limit per view requests.
2012-11-15 17:35:34 +04:00
"""
request = factory.get('/?page_size=5')
response = self.view(request).render()
2013-02-28 01:15:00 +04:00
self.assertEqual(response.data['count'], 13)
self.assertEqual(response.data['results'], self.data[:5])
2012-12-13 15:07:56 +04:00
### Tests for context in pagination serializers
2012-12-13 15:07:56 +04:00
class CustomField(serializers.Field):
def to_native(self, value):
if not 'view' in self.context:
raise RuntimeError("context isn't getting passed into custom field")
return "value"
class BasicModelSerializer(serializers.Serializer):
text = CustomField()
2013-01-24 12:58:19 +04:00
def __init__(self, *args, **kwargs):
super(BasicModelSerializer, self).__init__(*args, **kwargs)
if not 'view' in self.context:
raise RuntimeError("context isn't getting passed into serializer init")
2012-12-13 15:07:56 +04:00
class TestContextPassedToCustomField(TestCase):
def setUp(self):
BasicModel.objects.create(text='ala ma kota')
def test_with_pagination(self):
class ListView(generics.ListCreateAPIView):
model = BasicModel
serializer_class = BasicModelSerializer
paginate_by = 1
self.view = ListView.as_view()
request = factory.get('/')
response = self.view(request).render()
2013-02-28 01:15:00 +04:00
self.assertEqual(response.status_code, status.HTTP_200_OK)
### Tests for custom pagination serializers
class LinksSerializer(serializers.Serializer):
next = pagination.NextPageField(source='*')
prev = pagination.PreviousPageField(source='*')
class CustomPaginationSerializer(pagination.BasePaginationSerializer):
links = LinksSerializer(source='*') # Takes the page object as the source
total_results = serializers.Field(source='paginator.count')
results_field = 'objects'
class TestCustomPaginationSerializer(TestCase):
def setUp(self):
objects = ['john', 'paul', 'george', 'ringo']
paginator = Paginator(objects, 2)
self.page = paginator.page(1)
def test_custom_pagination_serializer(self):
request = RequestFactory().get('/foobar')
serializer = CustomPaginationSerializer(
instance=self.page,
context={'request': request}
)
expected = {
'links': {
'next': 'http://testserver/foobar?page=2',
'prev': None
},
'total_results': 4,
'objects': ['john', 'paul']
}
2013-02-28 01:15:00 +04:00
self.assertEqual(serializer.data, expected)