Avoided calling distinct on annotated fields in SearchFilter. (#6240)

Fixes #6094
This commit is contained in:
Andrzej Górski 2019-02-25 16:59:25 +01:00 committed by Carlton Gibson
parent 2daf6f1341
commit 317174b163
2 changed files with 36 additions and 0 deletions

View File

@ -85,6 +85,9 @@ class SearchFilter(BaseFilterBackend):
opts = queryset.model._meta opts = queryset.model._meta
if search_field[0] in self.lookup_prefixes: if search_field[0] in self.lookup_prefixes:
search_field = search_field[1:] search_field = search_field[1:]
# Annotated fields do not need to be distinct
if isinstance(queryset, models.QuerySet) and search_field in queryset.query.annotations:
return False
parts = search_field.split(LOOKUP_SEP) parts = search_field.split(LOOKUP_SEP)
for part in parts: for part in parts:
field = opts.get_field(part) field = opts.get_field(part)

View File

@ -5,6 +5,7 @@ import datetime
import pytest import pytest
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from django.db import models from django.db import models
from django.db.models.functions import Concat, Upper
from django.test import TestCase from django.test import TestCase
from django.test.utils import override_settings from django.test.utils import override_settings
from django.utils.six.moves import reload_module from django.utils.six.moves import reload_module
@ -329,6 +330,38 @@ class SearchFilterToManyTests(TestCase):
assert len(response.data) == 1 assert len(response.data) == 1
class SearchFilterAnnotatedSerializer(serializers.ModelSerializer):
title_text = serializers.CharField()
class Meta:
model = SearchFilterModel
fields = ('title', 'text', 'title_text')
class SearchFilterAnnotatedFieldTests(TestCase):
@classmethod
def setUpTestData(cls):
SearchFilterModel.objects.create(title='abc', text='def')
SearchFilterModel.objects.create(title='ghi', text='jkl')
def test_search_in_annotated_field(self):
class SearchListView(generics.ListAPIView):
queryset = SearchFilterModel.objects.annotate(
title_text=Upper(
Concat(models.F('title'), models.F('text'))
)
).all()
serializer_class = SearchFilterAnnotatedSerializer
filter_backends = (filters.SearchFilter,)
search_fields = ('title_text',)
view = SearchListView.as_view()
request = factory.get('/', {'search': 'ABCDEF'})
response = view(request)
assert len(response.data) == 1
assert response.data[0]['title_text'] == 'ABCDEF'
class OrderingFilterModel(models.Model): class OrderingFilterModel(models.Model):
title = models.CharField(max_length=20, verbose_name='verbose title') title = models.CharField(max_length=20, verbose_name='verbose title')
text = models.CharField(max_length=100) text = models.CharField(max_length=100)