mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-11-22 17:47:04 +03:00
Support for multiple filter classes
This commit is contained in:
parent
d71a5533f9
commit
3c2bb06660
|
@ -79,23 +79,22 @@ 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 provides an implementation which uses the [django-filter] package.
|
||||
## DjangoFilterBackend
|
||||
|
||||
To use REST framework's filtering backend, first install `django-filter`.
|
||||
To use REST framework's `DjangoFilterBackend`, first install `django-filter`.
|
||||
|
||||
pip install django-filter
|
||||
|
||||
You must also set the filter backend to `DjangoFilterBackend` in your settings:
|
||||
|
||||
REST_FRAMEWORK = {
|
||||
'FILTER_BACKEND': 'rest_framework.filters.DjangoFilterBackend'
|
||||
'DEFAULT_FILTER_BACKENDS': ['rest_framework.filters.DjangoFilterBackend']
|
||||
}
|
||||
|
||||
|
||||
## Specifying filter fields
|
||||
#### Specifying filter fields
|
||||
|
||||
If all you need is simple equality-based filtering, you can set a `filter_fields` attribute on the view, or viewset,
|
||||
listing the set of fields you wish to filter against.
|
||||
If all you need is simple equality-based filtering, you can set a `filter_fields` attribute on the view, or viewset, listing the set of fields you wish to filter against.
|
||||
|
||||
class ProductList(generics.ListAPIView):
|
||||
queryset = Product.objects.all()
|
||||
|
@ -106,7 +105,7 @@ This will automatically create a `FilterSet` class for the given fields, and wil
|
|||
|
||||
http://example.com/api/products?category=clothing&in_stock=True
|
||||
|
||||
## Specifying a FilterSet
|
||||
#### Specifying a FilterSet
|
||||
|
||||
For more advanced filtering requirements you can specify a `FilterSet` class that should be used by the view. For example:
|
||||
|
||||
|
@ -132,13 +131,13 @@ For more details on using filter sets see the [django-filter documentation][djan
|
|||
|
||||
**Hints & Tips**
|
||||
|
||||
* By default filtering is not enabled. If you want to use `DjangoFilterBackend` remember to make sure it is installed by using the `'FILTER_BACKEND'` setting.
|
||||
* By default filtering is not enabled. If you want to use `DjangoFilterBackend` remember to make sure it is installed by using the `'DEFAULT_FILTER_BACKENDS'` setting.
|
||||
* When using boolean fields, you should use the values `True` and `False` in the URL query parameters, rather than `0`, `1`, `true` or `false`. (The allowed boolean values are currently hardwired in Django's [NullBooleanSelect implementation][nullbooleanselect].)
|
||||
* `django-filter` supports filtering across relationships, using Django's double-underscore syntax.
|
||||
|
||||
---
|
||||
|
||||
### Filtering and object lookups
|
||||
## Filtering and object lookups
|
||||
|
||||
Note that if a filter backend is configured for a view, then as well as being used to filter list views, it will also be used to filter the querysets used for returning a single object.
|
||||
|
||||
|
@ -170,12 +169,12 @@ You can also provide your own generic filtering backend, or write an installable
|
|||
|
||||
To do so override `BaseFilterBackend`, and override the `.filter_queryset(self, request, queryset, view)` method. The method should return a new, filtered queryset.
|
||||
|
||||
To install the filter backend, set the `'FILTER_BACKEND'` key in your `'REST_FRAMEWORK'` setting, using the dotted import path of the filter backend class.
|
||||
To install the filter backend, set the `'DEFAULT_FILTER_BACKENDS'` key in your `'REST_FRAMEWORK'` setting, using the dotted import path of the filter backend class.
|
||||
|
||||
For example:
|
||||
|
||||
REST_FRAMEWORK = {
|
||||
'FILTER_BACKEND': 'custom_filters.CustomFilterBackend'
|
||||
'DEFAULT_FILTER_BACKENDS': ['custom_filters.CustomFilterBackend']
|
||||
}
|
||||
|
||||
[cite]: https://docs.djangoproject.com/en/dev/topics/db/queries/#retrieving-specific-objects-with-filters
|
||||
|
|
|
@ -77,7 +77,7 @@ The following attibutes are used to control pagination when used with list views
|
|||
|
||||
**Filtering**:
|
||||
|
||||
* `filter_backend` - The filter backend class that should be used for filtering the queryset. Defaults to the same value as the `FILTER_BACKEND` setting.
|
||||
* `filter_backends` - A list of filter backend classes that should be used for filtering the queryset. Defaults to the same value as the `DEFAULT_FILTER_BACKENDS` setting.
|
||||
|
||||
### Methods
|
||||
|
||||
|
|
|
@ -112,9 +112,10 @@ A class the determines the default serialization style for paginated responses.
|
|||
|
||||
Default: `rest_framework.pagination.PaginationSerializer`
|
||||
|
||||
#### FILTER_BACKEND
|
||||
#### DEFAULT_FILTER_BACKENDS
|
||||
|
||||
The filter backend class that should be used for generic filtering. If set to `None` then generic filtering is disabled.
|
||||
A list of filter backend classes that should be used for generic filtering.
|
||||
If set to `None` then generic filtering is disabled.
|
||||
|
||||
#### PAGINATE_BY
|
||||
|
||||
|
|
|
@ -86,6 +86,14 @@ Similarly, you can now easily include the primary key in hyperlinked relationshi
|
|||
model = Blog
|
||||
fields = ('url', 'id', 'title', 'created', 'comments')
|
||||
|
||||
## More flexible filtering
|
||||
|
||||
The `FILTER_BACKEND` setting has moved to pending deprecation, in favor of a `DEFAULT_FILTER_BACKENDS` setting that takes a *list* of filter backend classes, instead of a single filter backend class.
|
||||
|
||||
The generic view `filter_backend` attribute has also been moved to pending deprecation in favor of a `filter_backends` setting.
|
||||
|
||||
Being able to specify multiple filters will allow for more flexible, powerful behavior. New filter classes to handle searching and ordering of results are planned to be released shortly.
|
||||
|
||||
---
|
||||
|
||||
# API Changes
|
||||
|
|
|
@ -46,6 +46,7 @@ You can determine your currently installed version using `pip freeze`:
|
|||
* ModelSerializers support reverse relations in 'fields' option.
|
||||
* HyperLinkedModelSerializers support 'id' field in 'fields' option.
|
||||
* Cleaner generic views.
|
||||
* Support for multiple filter classes.
|
||||
* DecimalField support.
|
||||
* Bugfix: Fix issue with depth>1 on ModelSerializer.
|
||||
|
||||
|
|
|
@ -39,8 +39,8 @@ class GenericAPIView(views.APIView):
|
|||
pagination_serializer_class = api_settings.DEFAULT_PAGINATION_SERIALIZER_CLASS
|
||||
page_kwarg = 'page'
|
||||
|
||||
# The filter backend class to use for queryset filtering
|
||||
filter_backend = api_settings.FILTER_BACKEND
|
||||
# The filter backend classes to use for queryset filtering
|
||||
filter_backends = api_settings.DEFAULT_FILTER_BACKENDS
|
||||
|
||||
# The following attributes may be subject to change,
|
||||
# and should be considered private API.
|
||||
|
@ -54,6 +54,7 @@ class GenericAPIView(views.APIView):
|
|||
slug_url_kwarg = 'slug'
|
||||
slug_field = 'slug'
|
||||
allow_empty = True
|
||||
filter_backend = api_settings.FILTER_BACKEND
|
||||
|
||||
def get_serializer_context(self):
|
||||
"""
|
||||
|
@ -150,10 +151,20 @@ class GenericAPIView(views.APIView):
|
|||
method if you want to apply the configured filtering backend to the
|
||||
default queryset.
|
||||
"""
|
||||
if not self.filter_backend:
|
||||
filter_backends = self.filter_backends or []
|
||||
if not filter_backends and self.filter_backend:
|
||||
warnings.warn(
|
||||
'The `filter_backend` attribute and `FILTER_BACKEND` setting '
|
||||
'are due to be deprecated in favor of a `filter_backends` '
|
||||
'attribute and `DEFAULT_FILTER_BACKENDS` setting, that take '
|
||||
'a *list* of filter backend classes.',
|
||||
PendingDeprecationWarning, stacklevel=2
|
||||
)
|
||||
filter_backends = [self.filter_backend]
|
||||
|
||||
for backend in filter_backends:
|
||||
queryset = backend().filter_queryset(self.request, queryset, self)
|
||||
return queryset
|
||||
backend = self.filter_backend()
|
||||
return backend.filter_queryset(self.request, queryset, self)
|
||||
|
||||
########################
|
||||
### The following methods provide default implementations
|
||||
|
|
|
@ -29,6 +29,7 @@ from rest_framework.compat import six
|
|||
USER_SETTINGS = getattr(settings, 'REST_FRAMEWORK', None)
|
||||
|
||||
DEFAULTS = {
|
||||
# Base API policies
|
||||
'DEFAULT_RENDERER_CLASSES': (
|
||||
'rest_framework.renderers.JSONRenderer',
|
||||
'rest_framework.renderers.BrowsableAPIRenderer',
|
||||
|
@ -50,11 +51,15 @@ DEFAULTS = {
|
|||
|
||||
'DEFAULT_CONTENT_NEGOTIATION_CLASS':
|
||||
'rest_framework.negotiation.DefaultContentNegotiation',
|
||||
|
||||
# Genric view behavior
|
||||
'DEFAULT_MODEL_SERIALIZER_CLASS':
|
||||
'rest_framework.serializers.ModelSerializer',
|
||||
'DEFAULT_PAGINATION_SERIALIZER_CLASS':
|
||||
'rest_framework.pagination.PaginationSerializer',
|
||||
'DEFAULT_FILTER_BACKENDS': (),
|
||||
|
||||
# Throttling
|
||||
'DEFAULT_THROTTLE_RATES': {
|
||||
'user': None,
|
||||
'anon': None,
|
||||
|
@ -64,9 +69,6 @@ DEFAULTS = {
|
|||
'PAGINATE_BY': None,
|
||||
'PAGINATE_BY_PARAM': None,
|
||||
|
||||
# Filtering
|
||||
'FILTER_BACKEND': None,
|
||||
|
||||
# Authentication
|
||||
'UNAUTHENTICATED_USER': 'django.contrib.auth.models.AnonymousUser',
|
||||
'UNAUTHENTICATED_TOKEN': None,
|
||||
|
@ -95,6 +97,9 @@ DEFAULTS = {
|
|||
ISO_8601,
|
||||
),
|
||||
'TIME_FORMAT': ISO_8601,
|
||||
|
||||
# Pending deprecation
|
||||
'FILTER_BACKEND': None,
|
||||
}
|
||||
|
||||
|
||||
|
@ -108,6 +113,7 @@ IMPORT_STRINGS = (
|
|||
'DEFAULT_CONTENT_NEGOTIATION_CLASS',
|
||||
'DEFAULT_MODEL_SERIALIZER_CLASS',
|
||||
'DEFAULT_PAGINATION_SERIALIZER_CLASS',
|
||||
'DEFAULT_FILTER_BACKENDS',
|
||||
'FILTER_BACKEND',
|
||||
'UNAUTHENTICATED_USER',
|
||||
'UNAUTHENTICATED_TOKEN',
|
||||
|
|
Loading…
Reference in New Issue
Block a user