Added SearchFilter.get_search_fields() hook. (#6279)

This commit is contained in:
Allan Reyes 2019-02-19 08:18:14 -08:00 committed by Carlton Gibson
parent 1ece516d2d
commit d110454d4c
3 changed files with 41 additions and 1 deletions

View File

@ -218,6 +218,13 @@ For example:
By default, the search parameter is named `'search`', but this may be overridden with the `SEARCH_PARAM` setting. By default, the search parameter is named `'search`', but this may be overridden with the `SEARCH_PARAM` setting.
To dynamically change search fields based on request content, it's possible to subclass the `SearchFilter` and override the `get_search_fields()` function. For example, the following subclass will only search on `title` if the query parameter `title_only` is in the request:
class CustomSearchFilter(self, view, request):
if request.query_params.get('title_only'):
return ('title',)
return super(CustomSearchFilter, self).get_search_fields(view, request)
For more details, see the [Django documentation][search-django-admin]. For more details, see the [Django documentation][search-django-admin].
--- ---

View File

@ -53,6 +53,14 @@ class SearchFilter(BaseFilterBackend):
search_title = _('Search') search_title = _('Search')
search_description = _('A search term.') search_description = _('A search term.')
def get_search_fields(self, view, request):
"""
Search fields are obtained from the view, but the request is always
passed to this method. Sub-classes can override this method to
dynamically change the search fields based on request content.
"""
return getattr(view, 'search_fields', None)
def get_search_terms(self, request): def get_search_terms(self, request):
""" """
Search terms are set by a ?search=... query parameter, Search terms are set by a ?search=... query parameter,
@ -90,7 +98,7 @@ class SearchFilter(BaseFilterBackend):
return False return False
def filter_queryset(self, request, queryset, view): def filter_queryset(self, request, queryset, view):
search_fields = getattr(view, 'search_fields', None) search_fields = self.get_search_fields(view, request)
search_terms = self.get_search_terms(request) search_terms = self.get_search_terms(request)
if not search_fields or not search_terms: if not search_fields or not search_terms:

View File

@ -156,6 +156,31 @@ class SearchFilterTests(TestCase):
reload_module(filters) reload_module(filters)
def test_search_with_filter_subclass(self):
class CustomSearchFilter(filters.SearchFilter):
# Filter that dynamically changes search fields
def get_search_fields(self, view, request):
if request.query_params.get('title_only'):
return ('$title',)
return super(CustomSearchFilter, self).get_search_fields(view, request)
class SearchListView(generics.ListAPIView):
queryset = SearchFilterModel.objects.all()
serializer_class = SearchFilterSerializer
filter_backends = (CustomSearchFilter,)
search_fields = ('$title', '$text')
view = SearchListView.as_view()
request = factory.get('/', {'search': '^\w{3}$'})
response = view(request)
assert len(response.data) == 10
request = factory.get('/', {'search': '^\w{3}$', 'title_only': 'true'})
response = view(request)
assert response.data == [
{'id': 3, 'title': 'zzz', 'text': 'cde'}
]
class AttributeModel(models.Model): class AttributeModel(models.Model):
label = models.CharField(max_length=32) label = models.CharField(max_length=32)