diff options
| -rw-r--r-- | .travis.yml | 4 | ||||
| -rw-r--r-- | rest_framework/tests/pagination.py | 100 | ||||
| -rw-r--r-- | tox.ini | 12 |
3 files changed, 88 insertions, 28 deletions
diff --git a/.travis.yml b/.travis.yml index 4f2fe9ad..205feef9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,8 +17,8 @@ install: - "if [[ ${TRAVIS_PYTHON_VERSION::1} != '3' ]]; then pip install oauth2==1.5.211 --use-mirrors; fi" - "if [[ ${TRAVIS_PYTHON_VERSION::1} != '3' ]]; then pip install django-oauth-plus==2.0 --use-mirrors; fi" - "if [[ ${TRAVIS_PYTHON_VERSION::1} != '3' ]]; then pip install django-oauth2-provider==0.2.3 --use-mirrors; fi" - - "if [[ ${TRAVIS_PYTHON_VERSION::1} != '3' ]]; then pip install django-filter==0.5.4 --use-mirrors; fi" - - "if [[ ${TRAVIS_PYTHON_VERSION::1} == '3' ]]; then pip install https://github.com/alex/django-filter/tarball/master; fi" + - "if [[ ${DJANGO::11} == 'django==1.3' ]]; then pip install django-filter==0.5.4 --use-mirrors; fi" + - "if [[ ${DJANGO::11} != 'django==1.3' ]]; then pip install django-filter==0.6a1 --use-mirrors; fi" - export PYTHONPATH=. script: diff --git a/rest_framework/tests/pagination.py b/rest_framework/tests/pagination.py index 3c76ca7d..1a2d68a6 100644 --- a/rest_framework/tests/pagination.py +++ b/rest_framework/tests/pagination.py @@ -1,6 +1,7 @@ from __future__ import unicode_literals import datetime from decimal import Decimal +import django from django.core.paginator import Paginator from django.test import TestCase from django.test.client import RequestFactory @@ -20,21 +21,6 @@ class RootView(generics.ListCreateAPIView): 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 - filter_backend = filters.DjangoFilterBackend - - class DefaultPageSizeKwargView(generics.ListAPIView): """ View for testing default paginate_by_param usage @@ -119,17 +105,44 @@ class IntegrationTestPaginationAndFiltering(TestCase): {'id': obj.id, 'text': obj.text, 'decimal': obj.decimal, 'date': obj.date.isoformat()} 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): + def test_get_django_filter_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. """ + 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 + filter_backend = filters.DjangoFilterBackend + + view = FilterFieldsRootView.as_view() + + EXPECTED_NUM_QUERIES = 2 + if django.VERSION < (1, 4): + # On Django 1.3 we need to use django-filter 0.5.4 + # + # The filter objects there don't expose a `.count()` method, + # which means we only make a single query *but* it's a single + # query across *all* of the queryset, instead of a COUNT and then + # a SELECT with a LIMIT. + # + # Although this is fewer queries, it's actually a regression. + EXPECTED_NUM_QUERIES = 1 + request = factory.get('/?decimal=15.20') - response = self.view(request).render() + with self.assertNumQueries(EXPECTED_NUM_QUERIES): + response = view(request).render() self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.data['count'], 15) self.assertEqual(response.data['results'], self.data[:10]) @@ -137,7 +150,8 @@ class IntegrationTestPaginationAndFiltering(TestCase): self.assertEqual(response.data['previous'], None) request = factory.get(response.data['next']) - response = self.view(request).render() + with self.assertNumQueries(EXPECTED_NUM_QUERIES): + response = view(request).render() self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.data['count'], 15) self.assertEqual(response.data['results'], self.data[10:15]) @@ -145,7 +159,53 @@ class IntegrationTestPaginationAndFiltering(TestCase): self.assertNotEqual(response.data['previous'], None) request = factory.get(response.data['previous']) - response = self.view(request).render() + with self.assertNumQueries(EXPECTED_NUM_QUERIES): + response = view(request).render() + 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) + + def test_get_basic_paginated_filtered_root_view(self): + """ + Same as `test_get_django_filter_paginated_filtered_root_view`, + except using a custom filter backend instead of the django-filter + backend, + """ + + class DecimalFilterBackend(filters.BaseFilterBackend): + def filter_queryset(self, request, queryset, view): + return queryset.filter(decimal__lt=Decimal(request.GET['decimal'])) + + class BasicFilterFieldsRootView(generics.ListCreateAPIView): + model = FilterableItem + paginate_by = 10 + filter_backend = DecimalFilterBackend + + view = BasicFilterFieldsRootView.as_view() + + request = factory.get('/?decimal=15.20') + with self.assertNumQueries(2): + response = view(request).render() + 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']) + with self.assertNumQueries(2): + response = view(request).render() + 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']) + with self.assertNumQueries(2): + response = view(request).render() self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.data['count'], 15) self.assertEqual(response.data['results'], self.data[:10]) @@ -8,19 +8,19 @@ commands = {envpython} rest_framework/runtests/runtests.py [testenv:py3.3-django1.5] basepython = python3.3 deps = django==1.5 - -egit+git://github.com/alex/django-filter.git#egg=django_filter + django-filter==0.6a1 defusedxml==0.3 [testenv:py3.2-django1.5] basepython = python3.2 deps = django==1.5 - -egit+git://github.com/alex/django-filter.git#egg=django_filter + django-filter==0.6a1 defusedxml==0.3 [testenv:py2.7-django1.5] basepython = python2.7 deps = django==1.5 - django-filter==0.5.4 + django-filter==0.6a1 defusedxml==0.3 django-oauth-plus==2.0 oauth2==1.5.211 @@ -29,7 +29,7 @@ deps = django==1.5 [testenv:py2.6-django1.5] basepython = python2.6 deps = django==1.5 - django-filter==0.5.4 + django-filter==0.6a1 defusedxml==0.3 django-oauth-plus==2.0 oauth2==1.5.211 @@ -38,7 +38,7 @@ deps = django==1.5 [testenv:py2.7-django1.4] basepython = python2.7 deps = django==1.4.3 - django-filter==0.5.4 + django-filter==0.6a1 defusedxml==0.3 django-oauth-plus==2.0 oauth2==1.5.211 @@ -47,7 +47,7 @@ deps = django==1.4.3 [testenv:py2.6-django1.4] basepython = python2.6 deps = django==1.4.3 - django-filter==0.5.4 + django-filter==0.6a1 defusedxml==0.3 django-oauth-plus==2.0 oauth2==1.5.211 |
