14👍
Right now you are telling Django REST Framework to use the DjangoFilterBackend
for all views, but you are not telling it how the FilterSet
should be generated.
django-filter
will automatically generate a FilterSet
for all of the fields on a model if the fields
are set to None
. Django REST Framework will automatically generate a FilterSet
if filter_fields
are not set to None
, which means you won’t be able to use the default DjangoFilterBackend
.
You can create a custom DjangoFilterBackend
though, which will automatically generate the FilterSet
for all fields on the model.
from rest_framework.filters import DjangoFilterBackend
class AllDjangoFilterBackend(DjangoFilterBackend):
"""
A filter backend that uses django-filter.
"""
def get_filter_class(self, view, queryset=None):
"""
Return the django-filters `FilterSet` used to filter the queryset.
"""
filter_class = getattr(view, 'filter_class', None)
filter_fields = getattr(view, 'filter_fields', None)
if filter_class or filter_fields:
return super(AllDjangoFilterBackend, self).get_filter_class(self, view, queryset)
class AutoFilterSet(self.default_filter_set):
class Meta:
model = queryset.model
fields = None
return AutoFilterSet
This will still use the original filter backend for situations where the view defines a custom filter_class
or filter_fields
, but it will generate a custom FilterSet
for all other situations. Keep in mind that you shouldn’t allow fields which aren’t returned through the API to be filtered, as you are opening yourself up to future security issues (like people filtering a user list by passwords).
6👍
Ok I know it was a long time ago, but I was just faced with this question today (2019/11), so I decided to share this way that I think it is a little better:
Just use '__all__'
for filter fields
filter_fields = '__all__'
- Django south: changing field type in data migration
- Is there a way to access the context from everywhere in Django?
- Django admin different inlines for change and add view
- Create a new model which have all fields of currently existing model
2👍
Kevin Browns answer is fantastic, however may be slightly out of date now.
Running the AllDjangoFilterBackend
filter backend with django-filter==2.1.0 throws the following:
Setting 'Meta.model' without either 'Meta.fields' or 'Meta.exclude' has been deprecated since 0.15.0 and is now disallowed. Add an explicit 'Meta.fields' or 'Meta.exclude' to the AutoFilterSet class.
It seems that simply replacing fields = None
with exclude = ''
is sufficient to use all fields. Full code below:
from django_filters.rest_framework import DjangoFilterBackend
class AllDjangoFilterBackend(DjangoFilterBackend):
'''
Filters DRF views by any of the objects properties.
'''
def get_filter_class(self, view, queryset=None):
'''
Return the django-filters `FilterSet` used to filter the queryset.
'''
filter_class = getattr(view, 'filter_class', None)
filter_fields = getattr(view, 'filter_fields', None)
if filter_class or filter_fields:
return super().get_filter_class(self, view, queryset)
class AutoFilterSet(self.default_filter_set):
class Meta:
exclude = ''
model = queryset.model
return AutoFilterSet
Save this to your_project/your_app/filters.py (or similar) and then ensure your settings file contains:
REST_FRAMEWORK = {
'DEFAULT_FILTER_BACKENDS': (
'your_project.your_app.filters.AllDjangoFilterBackend'
),
}
1👍
I found this to work instead for drf 3.14.0 and django-filter 23.3
Updated from Stuart Buckingham’s answer
from django_filters.rest_framework import DjangoFilterBackend
class AllDjangoFilterBackend(DjangoFilterBackend):
"""
Filters DRF views by any of the objects properties.
"""
def get_filterset_class(self, view, queryset=None):
"""
Return the `FilterSet` class used to filter the queryset.
"""
filterset_class = getattr(view, "filterset_class", None)
filterset_fields = getattr(view, "filterset_fields", None)
if filterset_fields or filterset_class:
return super().get_filterset_class(view, queryset)
class AutoFilterSet(self.filterset_base):
class Meta:
model = queryset.model
fields = [field.name for field in queryset.model._meta.get_fields()]
return AutoFilterSet
0👍
Updated version of Stuart Buckingham comment for django-rest-framework 3.13.1:
from django_filters.rest_framework import DjangoFilterBackend
class AllDjangoFilterBackend(DjangoFilterBackend):
"""
A filter backend that uses django-filter.
"""
def get_filterset_class(self, view, queryset=None):
'''
Return the django-filters `FilterSet` used to filter the queryset.
'''
filter_class = getattr(view, 'filter_class', None)
filter_fields = getattr(view, 'filter_fields', None)
if filter_class or filter_fields:
return super().get_filter_class(self, view, queryset)
class AutoFilterSet(self.filterset_base):
class Meta:
fields = "__all__"
model = queryset.model
return AutoFilterSet