mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-11-26 03:23:59 +03:00
Use django-filter 0.6a1 and add database query count tests for paginated, filtered lists.
This commit is contained in:
parent
a798a5350a
commit
73ab7dc3f1
|
@ -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:
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
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):
|
||||||
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):
|
||||||
{'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):
|
||||||
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):
|
||||||
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])
|
||||||
|
|
12
tox.ini
12
tox.ini
|
@ -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
|
||||||
[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
|
||||||
[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
|
||||||
[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
|
||||||
|
|
Loading…
Reference in New Issue
Block a user