Skip to content

django_filters.DjangoFilterBackend #466

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
Sep 6, 2018
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 18 additions & 18 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,44 +5,44 @@ cache: pip
matrix:
include:
- python: 2.7
env: TOXENV=py27-django111-drf36
env: TOXENV=py27-df11-django111-drf36
- python: 2.7
env: TOXENV=py27-django111-drf37
env: TOXENV=py27-df11-django111-drf37
- python: 2.7
env: TOXENV=py27-django111-drf38
env: TOXENV=py27-df11-django111-drf38

- python: 3.4
env: TOXENV=py34-django111-drf36
env: TOXENV=py34-df20-django111-drf36
- python: 3.4
env: TOXENV=py34-django111-drf37
env: TOXENV=py34-df20-django111-drf37
- python: 3.4
env: TOXENV=py34-django111-drf38
env: TOXENV=py34-df20-django111-drf38
- python: 3.4
env: TOXENV=py34-django20-drf37
env: TOXENV=py34-df20-django20-drf37
- python: 3.4
env: TOXENV=py34-django20-drf38
env: TOXENV=py34-df20-django20-drf38

- python: 3.5
env: TOXENV=py35-django111-drf36
env: TOXENV=py35-df20-django111-drf36
- python: 3.5
env: TOXENV=py35-django111-drf37
env: TOXENV=py35-df20-django111-drf37
- python: 3.5
env: TOXENV=py35-django111-drf38
env: TOXENV=py35-df20-django111-drf38
- python: 3.5
env: TOXENV=py35-django20-drf37
env: TOXENV=py35-df20-django20-drf37
- python: 3.5
env: TOXENV=py35-django20-drf38
env: TOXENV=py35-df20-django20-drf38

- python: 3.6
env: TOXENV=py36-django111-drf36
env: TOXENV=py36-df20-django111-drf36
- python: 3.6
env: TOXENV=py36-django111-drf37
env: TOXENV=py36-df20-django111-drf37
- python: 3.6
env: TOXENV=py36-django111-drf38
env: TOXENV=py36-df20-django111-drf38
- python: 3.6
env: TOXENV=py36-django20-drf37
env: TOXENV=py36-df20-django20-drf37
- python: 3.6
env: TOXENV=py36-django20-drf38
env: TOXENV=py36-df20-django20-drf38

- python: 3.6
env: TOXENV=flake8
Expand Down
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
* Add `HyperlinkedRelatedField` and `SerializerMethodHyperlinkedRelatedField`. See [usage docs](docs/usage.md#related-fields)
* Add related urls support. See [usage docs](docs/usage.md#related-urls)
* Replaced binary `drf_example` sqlite3 db with a [fixture](example/fixtures/drf_example.yaml). See [usage docs](docs/usage.md#running-the-example-app).
* Add optional [jsonapi-style](http://jsonapi.org/format/) sort filter backend. See [usage docs](docs/usage.md#filter-backends)
* For naming consistency, renamed new `JsonApi`-prefix pagination classes to `JSONAPI`-prefix.
* Deprecates `JsonApiPageNumberPagination` and `JsonApiLimitOffsetPagination`
* Add optional [jsonapi-style](http://jsonapi.org/format/) filter backends. See [usage docs](docs/usage.md#filter-backends)

v2.5.0 - Released July 11, 2018

Expand Down
55 changes: 51 additions & 4 deletions docs/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ REST_FRAMEWORK = {
'DEFAULT_METADATA_CLASS': 'rest_framework_json_api.metadata.JSONAPIMetadata',
'DEFAULT_FILTER_BACKENDS': (
'rest_framework_json_api.filters.JSONAPIOrderingFilter',
'rest_framework_json_api.filters.JSONAPIDjangoFilter',
),
'TEST_REQUEST_RENDERER_CLASSES': (
'rest_framework_json_api.renderers.JSONRenderer',
Expand Down Expand Up @@ -92,14 +93,14 @@ class MyLimitPagination(JSONAPILimitOffsetPagination):

### Filter Backends

_This is the first of several anticipated JSON:API-specific filter backends._
_There are several anticipated JSON:API-specific filter backends in development. The first two are described below._

#### `JSONAPIOrderingFilter`
`JSONAPIOrderingFilter` implements the [JSON:API `sort`](http://jsonapi.org/format/#fetching-sorting) and uses
DRF's [ordering filter](http://django-rest-framework.readthedocs.io/en/latest/api-guide/filtering/#orderingfilter).

Per the JSON:API specification, "If the server does not support sorting as specified in the query parameter `sort`,
it **MUST** return `400 Bad Request`." For example, for `?sort=`abc,foo,def` where `foo` is a valid
it **MUST** return `400 Bad Request`." For example, for `?sort=abc,foo,def` where `foo` is a valid
field name and the other two are not valid:
```json
{
Expand All @@ -118,18 +119,64 @@ field name and the other two are not valid:
If you want to silently ignore bad sort fields, just use `rest_framework.filters.OrderingFilter` and set
`ordering_param` to `sort`.

#### `JSONAPIDjangoFilter`
`JSONAPIDjangoFilter` implements a Django ORM-style [JSON:API `filter`](http://jsonapi.org/format/#fetching-filtering)
using the [django-filter](https://django-filter.readthedocs.io/) package.

This filter is not part of the JSON:API standard per-se, other than the requirement
to use the `filter` keyword: It is an optional implementation of a style of
filtering in which each filter is an ORM expression as implemented by
`DjangoFilterBackend` and seems to be in alignment with an interpretation of the
[JSON:API _recommendations_](http://jsonapi.org/recommendations/#filtering), including relationship
chaining.

Filters can be:
- A resource field equality test:
`?filter[qty]=123`
- Apply other [field lookup](https://docs.djangoproject.com/en/stable/ref/models/querysets/#field-lookups) operators:
`?filter[name.icontains]=bar` or `?filter[name.isnull]=true`
- Membership in a list of values:
`?filter[name.in]=abc,123,zzz (name in ['abc','123','zzz'])`
- Filters can be combined for intersection (AND):
`?filter[qty]=123&filter[name.in]=abc,123,zzz&filter[...]`
- A related resource path can be used:
`?filter[inventory.item.partNum]=123456` (where `inventory.item` is the relationship path)

If you are also using [`rest_framework.filters.SearchFilter`](https://django-rest-framework.readthedocs.io/en/latest/api-guide/filtering/#searchfilter)
(which performs single parameter searchs across multiple fields) you'll want to customize the name of the query
parameter for searching to make sure it doesn't conflict with a field name defined in the filterset.
The recommended value is: `search_param="filter[search]"` but just make sure it's
`filter[_something_]` to comply with the jsonapi spec requirement to use the filter
keyword. The default is "search" unless overriden.

The filter returns a `400 Bad Request` error for invalid filter query parameters as in this example
for `GET http://127.0.0.1:8000/nopage-entries?filter[bad]=1`:
```json
{
"errors": [
{
"detail": "invalid filter[bad]",
"source": {
"pointer": "/data"
},
"status": "400"
}
]
}
```

#### Configuring Filter Backends

You can configure the filter backends either by setting the `REST_FRAMEWORK['DEFAULT_FILTER_BACKENDS']` as shown
in the [preceding](#configuration) example or individually add them as `.filter_backends` View attributes:
in the [example settings](#configuration) or individually add them as `.filter_backends` View attributes:

```python
from rest_framework_json_api import filters

class MyViewset(ModelViewSet):
queryset = MyModel.objects.all()
serializer_class = MyModelSerializer
filter_backends = (filters.JSONAPIOrderingFilter,)
filter_backends = (filters.JSONAPIOrderingFilter, filters.JSONAPIDjangoFilter,)
```


Expand Down
7 changes: 7 additions & 0 deletions example/settings/dev.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@
'debug_toolbar',
]

try:
import django_filters # noqa: 401
INSTALLED_APPS += ['django_filters']
except ImportError:
pass

TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
Expand Down Expand Up @@ -90,6 +96,7 @@
'DEFAULT_METADATA_CLASS': 'rest_framework_json_api.metadata.JSONAPIMetadata',
'DEFAULT_FILTER_BACKENDS': (
'rest_framework_json_api.filters.JSONAPIOrderingFilter',
'rest_framework_json_api.filters.JSONAPIDjangoFilter',
),
'TEST_REQUEST_RENDERER_CLASSES': (
'rest_framework_json_api.renderers.JSONRenderer',
Expand Down
Loading