Commit 73ab7dc3 by Tom Christie

Use django-filter 0.6a1 and add database query count tests for paginated, filtered lists.

parent a798a535
...@@ -17,8 +17,8 @@ install: ...@@ -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 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-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-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 [[ ${DJANGO::11} == 'django==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.6a1 --use-mirrors; fi"
- export PYTHONPATH=. - export PYTHONPATH=.
script: script:
......
from __future__ import unicode_literals from __future__ import unicode_literals
import datetime import datetime
from decimal import Decimal from decimal import Decimal
import django
from django.core.paginator import Paginator from django.core.paginator import Paginator
from django.test import TestCase from django.test import TestCase
from django.test.client import RequestFactory from django.test.client import RequestFactory
...@@ -20,21 +21,6 @@ class RootView(generics.ListCreateAPIView): ...@@ -20,21 +21,6 @@ class RootView(generics.ListCreateAPIView):
paginate_by = 10 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): class DefaultPageSizeKwargView(generics.ListAPIView):
""" """
View for testing default paginate_by_param usage View for testing default paginate_by_param usage
...@@ -119,17 +105,44 @@ class IntegrationTestPaginationAndFiltering(TestCase): ...@@ -119,17 +105,44 @@ class IntegrationTestPaginationAndFiltering(TestCase):
{'id': obj.id, 'text': obj.text, 'decimal': obj.decimal, 'date': obj.date.isoformat()} {'id': obj.id, 'text': obj.text, 'decimal': obj.decimal, 'date': obj.date.isoformat()}
for obj in self.objects.all() for obj in self.objects.all()
] ]
self.view = FilterFieldsRootView.as_view()
@unittest.skipUnless(django_filters, 'django-filters not installed') @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 GET requests to paginated filtered ListCreateAPIView should return
paginated results. The next and previous links should preserve the paginated results. The next and previous links should preserve the
filtered parameters. 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') 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.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['count'], 15) self.assertEqual(response.data['count'], 15)
self.assertEqual(response.data['results'], self.data[:10]) self.assertEqual(response.data['results'], self.data[:10])
...@@ -137,7 +150,8 @@ class IntegrationTestPaginationAndFiltering(TestCase): ...@@ -137,7 +150,8 @@ class IntegrationTestPaginationAndFiltering(TestCase):
self.assertEqual(response.data['previous'], None) self.assertEqual(response.data['previous'], None)
request = factory.get(response.data['next']) 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.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['count'], 15) self.assertEqual(response.data['count'], 15)
self.assertEqual(response.data['results'], self.data[10:15]) self.assertEqual(response.data['results'], self.data[10:15])
...@@ -145,7 +159,53 @@ class IntegrationTestPaginationAndFiltering(TestCase): ...@@ -145,7 +159,53 @@ class IntegrationTestPaginationAndFiltering(TestCase):
self.assertNotEqual(response.data['previous'], None) self.assertNotEqual(response.data['previous'], None)
request = factory.get(response.data['previous']) 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.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['count'], 15) self.assertEqual(response.data['count'], 15)
self.assertEqual(response.data['results'], self.data[:10]) self.assertEqual(response.data['results'], self.data[:10])
......
...@@ -8,19 +8,19 @@ commands = {envpython} rest_framework/runtests/runtests.py ...@@ -8,19 +8,19 @@ commands = {envpython} rest_framework/runtests/runtests.py
[testenv:py3.3-django1.5] [testenv:py3.3-django1.5]
basepython = python3.3 basepython = python3.3
deps = django==1.5 deps = django==1.5
-egit+git://github.com/alex/django-filter.git#egg=django_filter django-filter==0.6a1
defusedxml==0.3 defusedxml==0.3
[testenv:py3.2-django1.5] [testenv:py3.2-django1.5]
basepython = python3.2 basepython = python3.2
deps = django==1.5 deps = django==1.5
-egit+git://github.com/alex/django-filter.git#egg=django_filter django-filter==0.6a1
defusedxml==0.3 defusedxml==0.3
[testenv:py2.7-django1.5] [testenv:py2.7-django1.5]
basepython = python2.7 basepython = python2.7
deps = django==1.5 deps = django==1.5
django-filter==0.5.4 django-filter==0.6a1
defusedxml==0.3 defusedxml==0.3
django-oauth-plus==2.0 django-oauth-plus==2.0
oauth2==1.5.211 oauth2==1.5.211
...@@ -29,7 +29,7 @@ deps = django==1.5 ...@@ -29,7 +29,7 @@ deps = django==1.5
[testenv:py2.6-django1.5] [testenv:py2.6-django1.5]
basepython = python2.6 basepython = python2.6
deps = django==1.5 deps = django==1.5
django-filter==0.5.4 django-filter==0.6a1
defusedxml==0.3 defusedxml==0.3
django-oauth-plus==2.0 django-oauth-plus==2.0
oauth2==1.5.211 oauth2==1.5.211
...@@ -38,7 +38,7 @@ deps = django==1.5 ...@@ -38,7 +38,7 @@ deps = django==1.5
[testenv:py2.7-django1.4] [testenv:py2.7-django1.4]
basepython = python2.7 basepython = python2.7
deps = django==1.4.3 deps = django==1.4.3
django-filter==0.5.4 django-filter==0.6a1
defusedxml==0.3 defusedxml==0.3
django-oauth-plus==2.0 django-oauth-plus==2.0
oauth2==1.5.211 oauth2==1.5.211
...@@ -47,7 +47,7 @@ deps = django==1.4.3 ...@@ -47,7 +47,7 @@ deps = django==1.4.3
[testenv:py2.6-django1.4] [testenv:py2.6-django1.4]
basepython = python2.6 basepython = python2.6
deps = django==1.4.3 deps = django==1.4.3
django-filter==0.5.4 django-filter==0.6a1
defusedxml==0.3 defusedxml==0.3
django-oauth-plus==2.0 django-oauth-plus==2.0
oauth2==1.5.211 oauth2==1.5.211
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment