mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-08-03 03:50:11 +03:00
Merge 4af00465b2
into d2994e0596
This commit is contained in:
commit
85278fb3b9
|
@ -306,3 +306,61 @@ class DjangoObjectPermissionsFilter(BaseFilterBackend):
|
||||||
else:
|
else:
|
||||||
extra = {}
|
extra = {}
|
||||||
return get_objects_for_user(user, permission, queryset, **extra)
|
return get_objects_for_user(user, permission, queryset, **extra)
|
||||||
|
|
||||||
|
class SearchFieldFilter(SearchFilter):
|
||||||
|
# The URL query parameter used for the search on specific field.
|
||||||
|
# Use this filter to let the client choose the specific search field
|
||||||
|
# Example: ?search__name=x&search__last_name=y
|
||||||
|
search_param = api_settings.SEARCH_PARAM + '__'
|
||||||
|
lookup_prefixes = {
|
||||||
|
'^': 'istartswith',
|
||||||
|
'=': 'iexact',
|
||||||
|
'@': 'search',
|
||||||
|
'$': 'iregex',
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_search_terms(self, request):
|
||||||
|
"""
|
||||||
|
Search terms are set by the user as a suffix after the ?search__FIELDNAME=... query parameter,
|
||||||
|
and may be comma and/or whitespace delimited.
|
||||||
|
"""
|
||||||
|
params = [(key.replace(self.search_param, ''), request.query_params[key]) for
|
||||||
|
key in request.query_params.keys()
|
||||||
|
if key.startswith(self.search_param)]
|
||||||
|
|
||||||
|
return params
|
||||||
|
|
||||||
|
def filter_queryset(self, request, queryset, view):
|
||||||
|
|
||||||
|
valid_fields = getattr(view, 'search_fields', [])
|
||||||
|
search_terms = self.get_search_terms(request)
|
||||||
|
|
||||||
|
if not search_terms or not allowed_search_fields:
|
||||||
|
return queryset
|
||||||
|
|
||||||
|
if valid_fields != '__all__':
|
||||||
|
search_terms = [search_term for search_term in search_terms if
|
||||||
|
search_term[0] in valid_fields]
|
||||||
|
|
||||||
|
orm_lookups = [
|
||||||
|
self.construct_search(six.text_type(search_term[0]))
|
||||||
|
for search_term in search_terms
|
||||||
|
]
|
||||||
|
|
||||||
|
base = queryset
|
||||||
|
conditions = []
|
||||||
|
for search_term in search_terms:
|
||||||
|
queries = [
|
||||||
|
models.Q(**{orm_lookup: search_term[1]})
|
||||||
|
for orm_lookup in orm_lookups
|
||||||
|
]
|
||||||
|
conditions.append(reduce(operator.or_, queries))
|
||||||
|
queryset = queryset.filter(reduce(operator.and_, conditions))
|
||||||
|
|
||||||
|
if self.must_call_distinct(queryset, [search_term[0] for search_term in search_terms]):
|
||||||
|
# Filtering against a many-to-many field requires us to
|
||||||
|
# call queryset.distinct() in order to avoid duplicate items
|
||||||
|
# in the resulting queryset.
|
||||||
|
# We try to avoid this if possible, for performance reasons.
|
||||||
|
queryset = distinct(queryset, base)
|
||||||
|
return queryset
|
||||||
|
|
Loading…
Reference in New Issue
Block a user