Skip to content

Instantly share code, notes, and snippets.

@DataGreed
Created November 30, 2019 02:35
Show Gist options
  • Save DataGreed/aa379d1fb57b01a92d9006815912cd9a to your computer and use it in GitHub Desktop.
Save DataGreed/aa379d1fb57b01a92d9006815912cd9a to your computer and use it in GitHub Desktop.
Simple customized filter names for django-rest-framework (DRF)
from django.template import loader, Template, Context
from rest_framework.filters import SearchFilter
browsable_api_filter_template = """{% load i18n %}
<h2>{{ title }}</h2>
<p>{{description}}</p>
<form class="form-inline">
<div class="form-group">
<div class="input-group">
<input type="text" class="form-control" style="width: 350px" name="{{ param }}" value="{{ term }}">
<span class="input-group-btn">
<button class="btn btn-default" type="submit"><span class="glyphicon glyphicon-search" aria-hidden="true"></span> Filter</button>
</span>
</div>
</div>
</form>
"""
def __to_html(self, request, queryset, view):
"""
Redefined method does not require
search_fields field to exist in APIView
to render filters for browsable API
"""
term = self.get_search_terms(request)
term = term[0] if term else ''
context = Context({
'param': self.search_param,
'term': term,
# add title and description to recognize filters in web interface
'title': self.search_title,
'description': self.search_description
})
template = Template(browsable_api_filter_template)
return template.render(context)
def named_filter(
search_field_name,
search_fields,
search_title=None,
search_description=None):
"""
Dynamically creates and returns customized SearchFilter class
with custom search_param name
Use with APIView for filtering results with custom
parameter name.
E.g.
class UserListView(generics.ListAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
filter_backends = [named_filter(
'email',
['=email'],
"Email",
"Find user by specific email"
)]
# lets you filter by email parameter like this:
# url?email=some@example.com
Note: may break browsable API search when used.
:param search_field_name: name of the search field in URL params
:param search_fields: fields to search,
see https://www.django-rest-framework.org/api-guide/filtering/#searchfilter
:param search_description: verbose search description
:param search_title: verbose search title
:return:
"""
if not search_title:
search_title = search_field_name
if not search_description:
search_description = f"Filters results by {search_field_name}"
return type(f"{search_field_name}Filter", (SearchFilter,), {
"search_param": search_field_name,
"get_search_fields": lambda self, view, request: search_fields,
"to_html": __to_html,
"search_title": search_title,
"search_description": search_description
})
@DataGreed
Copy link
Author

Based on SearchFilter included in DRF

Usage:

class UserListView(generics.ListAPIView):
        queryset = User.objects.all()
        serializer_class = UserSerializer
        filter_backends = [named_filter(
                                'email',
                                ['=email'],
                                "Email",
                                "Find user by specific email"
                            )]
        # lets you filter by email parameter like this:
        # url?email=some@example.com

You can have as many filters at the same time as you want.
Schema generation works.

@DataGreed
Copy link
Author

tested with DRF 3.10

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment