Make default FILTER_BACKEND = None

This commit is contained in:
Tom Christie 2012-11-08 21:46:53 +00:00
parent c78b34d501
commit bc6f2a1703
6 changed files with 39 additions and 16 deletions

View File

@ -82,24 +82,30 @@ We can override `.get_queryset()` to deal with URLs such as `http://example.com/
As well as being able to override the default queryset, REST framework also includes support for generic filtering backends that allow you to easily construct complex filters that can be specified by the client using query parameters.
REST framework supports pluggable backends to implement filtering, and includes a default implementation which uses the [django-filter] package.
REST framework supports pluggable backends to implement filtering, and provides an implementation which uses the [django-filter] package.
To use REST framework's default filtering backend, first install `django-filter`.
pip install -e git+https://github.com/alex/django-filter.git#egg=django-filter
You must also set the filter backend to `DjangoFilterBackend` in your settings:
REST_FRAMEWORK = {
'FILTER_BACKEND': 'rest_framework.filters.DjangoFilterBackend'
}
**Note**: The currently supported version of `django-filter` is the `master` branch. A PyPI release is expected to be coming soon.
## Specifying filter fields
**TODO**: Document setting `.filter_fields` on the view.
## Specifying a FilterSet
**TODO**: Document setting `.filter_class` on the view.
**TODO**: Note support for `lookup_type`, double underscore relationship spanning, and ordering.
## Specifying filter fields
**TODO**: Document setting `.filter_fields` on the view.
**TODO**: Note that overiding `get_queryset()` can be used together with generic filtering
---

View File

@ -17,6 +17,10 @@ class DjangoFilterBackend(BaseFilterBackend):
"""
A filter backend that uses django-filter.
"""
default_filter_set = django_filters.FilterSet
def __init__(self):
assert django_filters, 'Using DjangoFilterBackend, but django-filter is not installed'
def get_filter_class(self, view):
"""
@ -24,20 +28,21 @@ class DjangoFilterBackend(BaseFilterBackend):
"""
filter_class = getattr(view, 'filter_class', None)
filter_fields = getattr(view, 'filter_fields', None)
filter_model = getattr(view, 'model', None)
if filter_class or filter_fields:
assert django_filters, 'django-filter is not installed'
view_model = getattr(view, 'model', None)
if filter_class:
assert issubclass(filter_class.Meta.model, filter_model), \
'%s is not a subclass of %s' % (filter_class.Meta.model, filter_model)
filter_model = filter_class.Meta.model
assert issubclass(filter_model, view_model), \
'FilterSet model %s does not match view model %s' % \
(filter_model, view_model)
return filter_class
if filter_fields:
class AutoFilterSet(django_filters.FilterSet):
class AutoFilterSet(self.default_filter_set):
class Meta:
model = filter_model
model = view_model
fields = filter_fields
return AutoFilterSet

View File

@ -107,6 +107,7 @@ import django
if django.VERSION < (1, 3):
INSTALLED_APPS += ('staticfiles',)
# If we're running on the Jenkins server we want to archive the coverage reports as XML.
import os
if os.environ.get('HUDSON_URL', None):

View File

@ -55,7 +55,7 @@ DEFAULTS = {
'anon': None,
},
'PAGINATE_BY': None,
'FILTER_BACKEND': 'rest_framework.filters.DjangoFilterBackend',
'FILTER_BACKEND': None,
'UNAUTHENTICATED_USER': 'django.contrib.auth.models.AnonymousUser',
'UNAUTHENTICATED_TOKEN': None,
@ -144,8 +144,15 @@ class APISettings(object):
if val and attr in self.import_strings:
val = perform_import(val, attr)
self.validate_setting(attr, val)
# Cache the result
setattr(self, attr, val)
return val
def validate_setting(self, attr, val):
if attr == 'FILTER_BACKEND' and val is not None:
# Make sure we can initilize the class
val()
api_settings = APISettings(USER_SETTINGS, DEFAULTS, IMPORT_STRINGS)

View File

@ -3,7 +3,7 @@ from decimal import Decimal
from django.test import TestCase
from django.test.client import RequestFactory
from django.utils import unittest
from rest_framework import generics, status
from rest_framework import generics, status, filters
from rest_framework.compat import django_filters
from rest_framework.tests.models import FilterableItem, BasicModel
@ -15,6 +15,7 @@ if django_filters:
class FilterFieldsRootView(generics.ListCreateAPIView):
model = FilterableItem
filter_fields = ['decimal', 'date']
filter_backend = filters.DjangoFilterBackend
# These class are used to test a filter class.
class SeveralFieldsFilter(django_filters.FilterSet):
@ -29,6 +30,7 @@ if django_filters:
class FilterClassRootView(generics.ListCreateAPIView):
model = FilterableItem
filter_class = SeveralFieldsFilter
filter_backend = filters.DjangoFilterBackend
# These classes are used to test a misconfigured filter class.
class MisconfiguredFilter(django_filters.FilterSet):
@ -41,6 +43,7 @@ if django_filters:
class IncorrectlyConfiguredRootView(generics.ListCreateAPIView):
model = FilterableItem
filter_class = MisconfiguredFilter
filter_backend = filters.DjangoFilterBackend
class IntegrationTestFiltering(TestCase):

View File

@ -4,7 +4,7 @@ from django.core.paginator import Paginator
from django.test import TestCase
from django.test.client import RequestFactory
from django.utils import unittest
from rest_framework import generics, status, pagination
from rest_framework import generics, status, pagination, filters
from rest_framework.compat import django_filters
from rest_framework.tests.models import BasicModel, FilterableItem
@ -31,6 +31,7 @@ if django_filters:
model = FilterableItem
paginate_by = 10
filter_class = DecimalFilter
filter_backend = filters.DjangoFilterBackend
class IntegrationTestPagination(TestCase):