diff --git a/rest_framework/filters.py b/rest_framework/filters.py index 47d9a0342c..531531efc3 100644 --- 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): diff --git a/tests/test_filters.py b/tests/test_filters.py index 9795230d6e..12fb858958 100644 --- 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): """ pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy