diff options
| author | Tom Christie | 2013-03-13 12:45:54 +0000 | 
|---|---|---|
| committer | Tom Christie | 2013-03-13 12:45:54 +0000 | 
| commit | 73ab7dc3f18c43d7bfb0c6f7581784d398cb36cf (patch) | |
| tree | 6e8b8ca027a9a3705078aff1216256348234e6d1 | |
| parent | a798a5350a6aa3100695d41d4d37ec7e2e073bdd (diff) | |
| download | django-rest-framework-73ab7dc3f18c43d7bfb0c6f7581784d398cb36cf.tar.bz2 | |
Use django-filter 0.6a1 and add database query count tests for paginated, filtered lists.
| -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 | 
