From 525f4b60189add04fe3e9827ddebfb17478aa61f Mon Sep 17 00:00:00 2001 From: Ryan P Kilby Date: Fri, 26 Jan 2018 06:40:24 -0500 Subject: [PATCH 1/2] Refactor backend filterset instantiation --- django_filters/rest_framework/backends.py | 38 ++++++++++++++--------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/django_filters/rest_framework/backends.py b/django_filters/rest_framework/backends.py index ff0e00c74..d401290d7 100644 --- a/django_filters/rest_framework/backends.py +++ b/django_filters/rest_framework/backends.py @@ -27,6 +27,14 @@ def template(self): return 'django_filters/rest_framework/crispy_form.html' return 'django_filters/rest_framework/form.html' + def get_filterset(self, request, queryset, view): + filterset_class = self.get_filterset_class(view, queryset) + if filterset_class is None: + return None + + kwargs = self.get_filterset_kwargs(request, queryset, view) + return filterset_class(**kwargs) + def get_filterset_class(self, view, queryset=None): """ Return the `FilterSet` class used to filter the queryset. @@ -71,27 +79,29 @@ class Meta(MetaBase): return None + def get_filterset_kwargs(self, request, queryset, view): + return { + 'data': request.query_params, + 'queryset': queryset, + 'request': request, + } + def filter_queryset(self, request, queryset, view): - filterset_class = self.get_filterset_class(view, queryset) + filterset = self.get_filterset(request, queryset, view) + if filterset is None: + return queryset - if filterset_class: - filterset = filterset_class(request.query_params, queryset=queryset, request=request) - if not filterset.is_valid() and self.raise_exception: - raise utils.translate_validation(filterset.errors) - return filterset.qs - return queryset + if not filterset.is_valid() and self.raise_exception: + raise utils.translate_validation(filterset.errors) + return filterset.qs def to_html(self, request, queryset, view): - filterset_class = self.get_filterset_class(view, queryset) - if not filterset_class: + filterset = self.get_filterset(request, queryset, view) + if filterset is None: return None - filterset = filterset_class(request.query_params, queryset=queryset, request=request) template = loader.get_template(self.template) - context = { - 'filter': filterset - } - + context = {'filter': filterset} return template.render(context, request) def get_coreschema_field(self, field): From 009b30fe1c91aa2066ae5d0cd26e52cfdbcda989 Mon Sep 17 00:00:00 2001 From: Ryan P Kilby Date: Fri, 26 Jan 2018 08:50:36 -0500 Subject: [PATCH 2/2] Add DRF docs for filterset customization --- docs/guide/rest_framework.txt | 39 +++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/docs/guide/rest_framework.txt b/docs/guide/rest_framework.txt index 4eaf54c90..480c819a7 100644 --- a/docs/guide/rest_framework.txt +++ b/docs/guide/rest_framework.txt @@ -105,6 +105,45 @@ You may bypass creating a ``FilterSet`` by instead adding ``filter_fields`` to y fields = ('category', 'in_stock') +Overriding FilterSet creation +----------------------------- + +``FilterSet`` creation can be customized by overriding the following methods on the backend class: + +* ``.get_filterset(self, request, queryset, view)`` +* ``.get_filterset_class(self, view, queryset=None)`` +* ``.get_filterset_kwargs(self, request, queryset, view)`` + +You can override these methods on a case-by-case basis for each view, creating unique backends, or these methods can be used to write your own hooks to the view class. + +.. code-block:: python + + class MyFilterBackend(filters.DjangoFilterBackend): + def get_filterset_kwargs(self, request, queryset, view): + kwargs = super().get_filterset_kwargs(request, queryset, view) + + # merge filterset kwargs provided by view class + if hasattr(view, 'get_filterset_kwargs'): + kwargs.update(view.get_filterset_kwargs()) + + return kwargs + + + class BooksFilter(filters.FitlerSet): + def __init__(self, *args, author=None, **kwargs): + super().__init__(*args, **kwargs) + # do something w/ author + + + class BookViewSet(viewsets.ModelViewSet): + filter_backends = [MyFilterBackend] + filter_class = BookFilter + + def get_filteset_kwargs(self): + return { + 'author': self.get_author(), + } + Schema Generation with Core API -------------------------------