diff --git a/docs/api-guide/filtering.md b/docs/api-guide/filtering.md index e65c6bf4f..6f4648cfd 100644 --- a/docs/api-guide/filtering.md +++ b/docs/api-guide/filtering.md @@ -260,6 +260,7 @@ The search behavior may be restricted by prepending various characters to the `s * '^' Starts-with search. * '=' Exact matches. * '@' Full-text search. (Currently only supported Django's MySQL backend.) +* '$' Regex search. For example: diff --git a/rest_framework/filters.py b/rest_framework/filters.py index e05d31ae3..931263670 100644 --- a/rest_framework/filters.py +++ b/rest_framework/filters.py @@ -94,6 +94,8 @@ class SearchFilter(BaseFilterBackend): return "%s__iexact" % field_name[1:] elif field_name.startswith('@'): return "%s__search" % field_name[1:] + if field_name.startswith('$'): + return "%s__iregex" % field_name[1:] else: return "%s__icontains" % field_name diff --git a/tests/test_filters.py b/tests/test_filters.py index 9db685c28..0610b0855 100644 --- a/tests/test_filters.py +++ b/tests/test_filters.py @@ -407,6 +407,23 @@ class SearchFilterTests(TestCase): ] ) + def test_regexp_search(self): + class SearchListView(generics.ListAPIView): + queryset = SearchFilterModel.objects.all() + serializer_class = SearchFilterSerializer + filter_backends = (filters.SearchFilter,) + search_fields = ('$title', '$text') + + view = SearchListView.as_view() + request = factory.get('/', {'search': 'z{2} ^b'}) + response = view(request) + self.assertEqual( + response.data, + [ + {'id': 2, 'title': 'zz', 'text': 'bcd'} + ] + ) + def test_search_with_nonstandard_search_param(self): with override_settings(REST_FRAMEWORK={'SEARCH_PARAM': 'query'}): reload_module(filters)