aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTom Christie2013-03-13 12:45:54 +0000
committerTom Christie2013-03-13 12:45:54 +0000
commit73ab7dc3f18c43d7bfb0c6f7581784d398cb36cf (patch)
tree6e8b8ca027a9a3705078aff1216256348234e6d1
parenta798a5350a6aa3100695d41d4d37ec7e2e073bdd (diff)
downloaddjango-rest-framework-73ab7dc3f18c43d7bfb0c6f7581784d398cb36cf.tar.bz2
Use django-filter 0.6a1 and add database query count tests for paginated, filtered lists.
-rw-r--r--.travis.yml4
-rw-r--r--rest_framework/tests/pagination.py100
-rw-r--r--tox.ini12
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])
diff --git a/tox.ini b/tox.ini
index 677c5d42..d62359a5 100644
--- a/tox.ini
+++ b/tox.ini
@@ -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