Skip to content

Commit e939e17

Browse files
Base automatic filterset model on the queryset model. Fixes encode#834.
1 parent d624141 commit e939e17

File tree

2 files changed

+27
-13
lines changed

2 files changed

+27
-13
lines changed

rest_framework/filters.py

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -32,40 +32,33 @@ class DjangoFilterBackend(BaseFilterBackend):
3232
def __init__(self):
3333
assert django_filters, 'Using DjangoFilterBackend, but django-filter is not installed'
3434

35-
def get_filter_class(self, view):
35+
def get_filter_class(self, view, queryset=None):
3636
"""
3737
Return the django-filters `FilterSet` used to filter the queryset.
3838
"""
3939
filter_class = getattr(view, 'filter_class', None)
4040
filter_fields = getattr(view, 'filter_fields', None)
41-
model_cls = getattr(view, 'model', None)
42-
queryset = getattr(view, 'queryset', None)
43-
if model_cls is None and queryset is not None:
44-
model_cls = queryset.model
4541

4642
if filter_class:
4743
filter_model = filter_class.Meta.model
4844

49-
assert issubclass(filter_model, model_cls), \
50-
'FilterSet model %s does not match view model %s' % \
51-
(filter_model, model_cls)
45+
assert issubclass(filter_model, queryset.model), \
46+
'FilterSet model %s does not match queryset model %s' % \
47+
(filter_model, queryset.model)
5248

5349
return filter_class
5450

5551
if filter_fields:
56-
assert model_cls is not None, 'Cannot use DjangoFilterBackend ' \
57-
'on a view which does not have a .model or .queryset attribute.'
58-
5952
class AutoFilterSet(self.default_filter_set):
6053
class Meta:
61-
model = model_cls
54+
model = queryset.model
6255
fields = filter_fields
6356
return AutoFilterSet
6457

6558
return None
6659

6760
def filter_queryset(self, request, queryset, view):
68-
filter_class = self.get_filter_class(view)
61+
filter_class = self.get_filter_class(view, queryset)
6962

7063
if filter_class:
7164
return filter_class(request.QUERY_PARAMS, queryset=queryset).qs

rest_framework/tests/filters.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,19 @@ class FilterFieldsQuerysetView(generics.ListCreateAPIView):
7070
filter_fields = ['decimal', 'date']
7171
filter_backend = filters.DjangoFilterBackend
7272

73+
class GetQuerysetView(generics.ListCreateAPIView):
74+
serializer_class = FilterableItemSerializer
75+
filter_class = SeveralFieldsFilter
76+
filter_backend = filters.DjangoFilterBackend
77+
78+
def get_queryset(self):
79+
return FilterableItem.objects.all()
80+
7381
urlpatterns = patterns('',
7482
url(r'^(?P<pk>\d+)/$', FilterClassDetailView.as_view(), name='detail-view'),
7583
url(r'^$', FilterClassRootView.as_view(), name='root-view'),
84+
url(r'^get-queryset/$', GetQuerysetView.as_view(),
85+
name='get-queryset-view'),
7686
)
7787

7888

@@ -147,6 +157,17 @@ def test_filter_with_queryset(self):
147157
expected_data = [f for f in self.data if f['decimal'] == search_decimal]
148158
self.assertEqual(response.data, expected_data)
149159

160+
@unittest.skipUnless(django_filters, 'django-filters not installed')
161+
def test_filter_with_get_queryset_only(self):
162+
"""
163+
Regression test for #834.
164+
"""
165+
view = GetQuerysetView.as_view()
166+
request = factory.get('/get-queryset/')
167+
view(request).render()
168+
# Used to raise "issubclass() arg 2 must be a class or tuple of classes"
169+
# here when neither `model' nor `queryset' was specified.
170+
150171
@unittest.skipUnless(django_filters, 'django-filters not installed')
151172
def test_get_filtered_class_root_view(self):
152173
"""

0 commit comments

Comments
 (0)