Commit b4b2dc18 by Tom Christie

Clean-up refactoring of SearchFilter implementation

parent aa4cd7e9
...@@ -50,6 +50,13 @@ def total_seconds(timedelta): ...@@ -50,6 +50,13 @@ def total_seconds(timedelta):
return (timedelta.days * 86400.0) + float(timedelta.seconds) + (timedelta.microseconds / 1000000.0) return (timedelta.days * 86400.0) + float(timedelta.seconds) + (timedelta.microseconds / 1000000.0)
def distinct(queryset, base):
if settings.DATABASES[queryset.db]["ENGINE"] == "django.db.backends.oracle":
# distinct analogue for Oracle users
return base.filter(pk__in=set(queryset.values_list('pk', flat=True)))
return queryset.distinct()
# OrderedDict only available in Python 2.7. # OrderedDict only available in Python 2.7.
# This will always be the case in Django 1.7 and above, as these versions # This will always be the case in Django 1.7 and above, as these versions
# no longer support Python 2.6. # no longer support Python 2.6.
......
...@@ -7,12 +7,13 @@ from __future__ import unicode_literals ...@@ -7,12 +7,13 @@ from __future__ import unicode_literals
import operator import operator
from functools import reduce from functools import reduce
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from django.db import models from django.db import models
from django.utils import six from django.utils import six
from rest_framework.compat import django_filters, get_model_name, guardian from rest_framework.compat import (
distinct, django_filters, get_model_name, guardian
)
from rest_framework.settings import api_settings from rest_framework.settings import api_settings
FilterSet = django_filters and django_filters.FilterSet or None FilterSet = django_filters and django_filters.FilterSet or None
...@@ -99,25 +100,27 @@ class SearchFilter(BaseFilterBackend): ...@@ -99,25 +100,27 @@ class SearchFilter(BaseFilterBackend):
def filter_queryset(self, request, queryset, view): def filter_queryset(self, request, queryset, view):
search_fields = getattr(view, 'search_fields', None) search_fields = getattr(view, 'search_fields', None)
if not search_fields: orm_lookups = [
return queryset self.construct_search(six.text_type(search_field))
for search_field in search_fields
original_queryset = queryset ]
orm_lookups = [self.construct_search(six.text_type(search_field)) search_terms = self.get_search_terms(request)
for search_field in search_fields]
for search_term in self.get_search_terms(request): if not search_fields or not search_terms:
or_queries = [models.Q(**{orm_lookup: search_term}) return queryset
for orm_lookup in orm_lookups]
queryset = queryset.filter(reduce(operator.or_, or_queries))
if settings.DATABASES[queryset.db]["ENGINE"] == "django.db.backends.oracle": base = queryset
# distinct analogue for Oracle users for search_term in search_terms:
queryset = original_queryset.filter(pk__in=set(queryset.values_list('pk', flat=True))) queries = [
else: models.Q(**{orm_lookup: search_term})
queryset = queryset.distinct() for orm_lookup in orm_lookups
]
queryset = queryset.filter(reduce(operator.or_, queries))
return queryset # Filtering against a many-to-many field requires us to
# call queryset.distinct() in order to avoid duplicate items
# in the resulting queryset.
return distinct(queryset, base)
class OrderingFilter(BaseFilterBackend): class OrderingFilter(BaseFilterBackend):
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment