Repository: encode/django-rest-framework

Issue:
FilterSet proxying broken in 3.5
The 3.5 release seems to have broken custom FilterSet classes with #4593. Any FilterSets I define behave as if no filters were included, returning all results.

The tests don't currently cover the new behaviour:
https://codecov.io/gh/tomchristie/django-rest-framework/src/1bd35ad35553e1be91df85dadb163c240aa51498/rest_framework/filters.py#L40
## Checklist
- [x] I have verified that that issue exists against the `master` branch of Django REST framework.
- [x] I have searched for similar issues in both open and closed tickets and cannot find a duplicate.
- [x] This is not a usage question. (Those should be directed to the [discussion group](https://groups.google.com/forum/#!forum/django-rest-framework) instead.)
- [x] This cannot be dealt with as a third party library. (We prefer new functionality to be [in the form of third party libraries](http://www.django-rest-framework.org/topics/third-party-resources/#about-third-party-packages) where possible.)
- [x] I have reduced the issue to the simplest possible case.
- [x] I have included a failing test as a pull request. (If you are unable to do so we can still accept the issue.)
## Steps to reproduce
## Expected behavior

FilterSet behaves the same as django_filters FilterSet.
## Actual behavior

FilterSet doesn't filter properly. Filtering always returns the whole queryset.



Discussion:

Resolving patch:
diff --git a/rest_framework/filters.py b/rest_framework/filters.py
--- a/rest_framework/filters.py
+++ b/rest_framework/filters.py
@@ -37,15 +37,32 @@ def get_schema_fields(self, view):
         return []
 
 
-class FilterSet(object):
-    def __new__(cls, *args, **kwargs):
-        warnings.warn(
-            "The built in 'rest_framework.filters.FilterSet' is pending deprecation. "
-            "You should use 'django_filters.rest_framework.FilterSet' instead.",
-            PendingDeprecationWarning
-        )
-        from django_filters.rest_framework import FilterSet
-        return FilterSet(*args, **kwargs)
+if django_filters:
+    from django_filters.filterset import FilterSetMetaclass as DFFilterSetMetaclass
+    from django_filters.rest_framework.filterset import FilterSet as DFFilterSet
+
+    class FilterSetMetaclass(DFFilterSetMetaclass):
+        def __new__(cls, name, bases, attrs):
+            warnings.warn(
+                "The built in 'rest_framework.filters.FilterSet' is pending deprecation. "
+                "You should use 'django_filters.rest_framework.FilterSet' instead.",
+                PendingDeprecationWarning
+            )
+            return super(FilterSetMetaclass, cls).__new__(cls, name, bases, attrs)
+    _BaseFilterSet = DFFilterSet
+else:
+    # Dummy metaclass just so we can give a user-friendly error message.
+    class FilterSetMetaclass(type):
+        def __init__(self, name, bases, attrs):
+            # Assert only on subclasses, so we can define FilterSet below.
+            if bases != (object,):
+                assert False, 'django-filter must be installed to use the `FilterSet` class'
+            super(FilterSetMetaclass, self).__init__(name, bases, attrs)
+    _BaseFilterSet = object
+
+
+class FilterSet(six.with_metaclass(FilterSetMetaclass, _BaseFilterSet)):
+    pass
 
 
 class DjangoFilterBackend(BaseFilterBackend):


Test patch:
diff --git a/tests/test_filters.py b/tests/test_filters.py
--- a/tests/test_filters.py
+++ b/tests/test_filters.py
@@ -79,12 +79,23 @@ class Meta:
             model = BaseFilterableItem
             fields = '__all__'
 
+    # Test the same filter using the deprecated internal FilterSet class.
+    class BaseFilterableItemFilterWithProxy(filters.FilterSet):
+        text = django_filters.CharFilter()
+
+        class Meta:
+            model = BaseFilterableItem
+            fields = '__all__'
+
     class BaseFilterableItemFilterRootView(generics.ListCreateAPIView):
         queryset = FilterableItem.objects.all()
         serializer_class = FilterableItemSerializer
         filter_class = BaseFilterableItemFilter
         filter_backends = (filters.DjangoFilterBackend,)
 
+    class BaseFilterableItemFilterWithProxyRootView(BaseFilterableItemFilterRootView):
+        filter_class = BaseFilterableItemFilterWithProxy
+
     # Regression test for #814
     class FilterFieldsQuerysetView(generics.ListCreateAPIView):
         queryset = FilterableItem.objects.all()
@@ -296,6 +307,18 @@ def test_base_model_filter(self):
         self.assertEqual(response.status_code, status.HTTP_200_OK)
         self.assertEqual(len(response.data), 1)
 
+    @unittest.skipUnless(django_filters, 'django-filter not installed')
+    def test_base_model_filter_with_proxy(self):
+        """
+        The `get_filter_class` model checks should allow base model filters.
+        """
+        view = BaseFilterableItemFilterWithProxyRootView.as_view()
+
+        request = factory.get('/?text=aaa')
+        response = view(request).render()
+        self.assertEqual(response.status_code, status.HTTP_200_OK)
+        self.assertEqual(len(response.data), 1)
+
     @unittest.skipUnless(django_filters, 'django-filter not installed')
     def test_unknown_filter(self):
         """