Skip to content

Let SearchFilter subclasses dynamically set search fields #6279

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 19, 2019
Merged

Let SearchFilter subclasses dynamically set search fields #6279

merged 1 commit into from
Feb 19, 2019

Conversation

allanbreyes
Copy link
Contributor

@allanbreyes allanbreyes commented Oct 25, 2018

Description

This pull request refactors #filter_queryset and extracts a #get_search_fields method, passing in the request in as a second argument (currently unused). This allows subclasses to override this method and dynamically set search fields (vs. overriding the entire #filter_queryset method). A few example use cases:

  1. Suppose you have 5 search fields, with email being one of them. If you run the search terms through a regex and recognize an email, you can dynamically set the search fields only to email. (This avoids wasteful searches on the other 4 fields.)

  2. Suppose the default search fields are ("^book_title",). In combination with overriding the #get_search_terms method, a subclass might implement a light lexer/parser to recognize when a search term is encased in quotes, e.g. "Green Eggs and Ham" to translate to an exact search of that string on book_title. This is how Google searches (roughly) work. Otherwise, the existing behavior would do a prefix search on ['"Green", 'Eggs', 'and', 'Ham"'].

  3. Handling more complex search configurations, e.g. Google advanced search.

Thanks! ❤️ DRF!

Copy link
Collaborator

@carltongibson carltongibson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's the obvious "docs & tests" but this seems like a nice/small enough adjustment.

@allanbreyes
Copy link
Contributor Author

👍 Happy to add any unit tests to ensure forward compatibility for consumers who might subclass it.

@allanbreyes
Copy link
Contributor Author

I added a test that ensures that subclasses can properly inherit from both get_search_fields and get_search_terms. That would cover really complex cases (i.e. example 2) where a consumer would want to hook into both methods.

@allanbreyes
Copy link
Contributor Author

@carltongibson @rpkilby any more thoughts on this? Thank you!

Copy link
Member

@rpkilby rpkilby left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple of minor nitpicks, but this otherwise looks good to me 👍

@rpkilby rpkilby added this to the 3.9.1 Release milestone Nov 21, 2018
@allanbreyes
Copy link
Contributor Author

Apologies for the delay; been a bit busy at work. Thanks for reviewing, @rpkilby!

@rpkilby
Copy link
Member

rpkilby commented Dec 3, 2018

Thanks!

Copy link
Collaborator

@carltongibson carltongibson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @allanbreyes.

Super. Thank you. Welcome aboard! 🎁

@carltongibson carltongibson merged commit d110454 into encode:master Feb 19, 2019
@allanbreyes allanbreyes deleted the get_search_fields branch February 19, 2019 18:57
@@ -218,6 +218,13 @@ For example:

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):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you mean:

class CustomSearchFilter(SearchFilter):
    def get_search_fields(self, view, request):
      ...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, someone else noticed this in #6487.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for catching! Apologies for the mistake :(

search_fields = ('$title', '$text')

view = SearchListView.as_view()
request = factory.get('/', {'search': '^\w{3}$'})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use raw strings to avoid Python warnings.

pchiquet pushed a commit to pchiquet/django-rest-framework that referenced this pull request Nov 17, 2020
sigvef pushed a commit to sigvef/django-rest-framework that referenced this pull request Dec 3, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants