mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-11-23 01:57:00 +03:00
Merge pull request #5264 from rpkilby/search-filter-reverse
Fix SearchFilter to-many behavior/performance
This commit is contained in:
commit
8a8389bd4b
|
@ -140,12 +140,14 @@ class SearchFilter(BaseFilterBackend):
|
||||||
]
|
]
|
||||||
|
|
||||||
base = queryset
|
base = queryset
|
||||||
|
conditions = []
|
||||||
for search_term in search_terms:
|
for search_term in search_terms:
|
||||||
queries = [
|
queries = [
|
||||||
models.Q(**{orm_lookup: search_term})
|
models.Q(**{orm_lookup: search_term})
|
||||||
for orm_lookup in orm_lookups
|
for orm_lookup in orm_lookups
|
||||||
]
|
]
|
||||||
queryset = queryset.filter(reduce(operator.or_, queries))
|
conditions.append(reduce(operator.or_, queries))
|
||||||
|
queryset = queryset.filter(reduce(operator.and_, conditions))
|
||||||
|
|
||||||
if self.must_call_distinct(queryset, search_fields):
|
if self.must_call_distinct(queryset, search_fields):
|
||||||
# Filtering against a many-to-many field requires us to
|
# Filtering against a many-to-many field requires us to
|
||||||
|
|
|
@ -5,6 +5,7 @@ import unittest
|
||||||
import warnings
|
import warnings
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
|
||||||
|
import django
|
||||||
import pytest
|
import pytest
|
||||||
from django.conf.urls import url
|
from django.conf.urls import url
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
|
@ -645,6 +646,51 @@ class SearchFilterM2MTests(TestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class Blog(models.Model):
|
||||||
|
name = models.CharField(max_length=20)
|
||||||
|
|
||||||
|
|
||||||
|
class Entry(models.Model):
|
||||||
|
blog = models.ForeignKey(Blog, on_delete=models.CASCADE)
|
||||||
|
headline = models.CharField(max_length=120)
|
||||||
|
pub_date = models.DateField(null=True)
|
||||||
|
|
||||||
|
|
||||||
|
class BlogSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = Blog
|
||||||
|
fields = '__all__'
|
||||||
|
|
||||||
|
|
||||||
|
class SearchFilterToManyTests(TestCase):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpTestData(cls):
|
||||||
|
b1 = Blog.objects.create(name='Blog 1')
|
||||||
|
b2 = Blog.objects.create(name='Blog 2')
|
||||||
|
|
||||||
|
# Multiple entries on Lennon published in 1979 - distinct should deduplicate
|
||||||
|
Entry.objects.create(blog=b1, headline='Something about Lennon', pub_date=datetime.date(1979, 1, 1))
|
||||||
|
Entry.objects.create(blog=b1, headline='Another thing about Lennon', pub_date=datetime.date(1979, 6, 1))
|
||||||
|
|
||||||
|
# Entry on Lennon *and* a separate entry in 1979 - should not match
|
||||||
|
Entry.objects.create(blog=b2, headline='Something unrelated', pub_date=datetime.date(1979, 1, 1))
|
||||||
|
Entry.objects.create(blog=b2, headline='Retrospective on Lennon', pub_date=datetime.date(1990, 6, 1))
|
||||||
|
|
||||||
|
@unittest.skipIf(django.VERSION < (1, 9), "Django 1.8 does not support transforms")
|
||||||
|
def test_multiple_filter_conditions(self):
|
||||||
|
class SearchListView(generics.ListAPIView):
|
||||||
|
queryset = Blog.objects.all()
|
||||||
|
serializer_class = BlogSerializer
|
||||||
|
filter_backends = (filters.SearchFilter,)
|
||||||
|
search_fields = ('=name', 'entry__headline', '=entry__pub_date__year')
|
||||||
|
|
||||||
|
view = SearchListView.as_view()
|
||||||
|
request = factory.get('/', {'search': 'Lennon,1979'})
|
||||||
|
response = view(request)
|
||||||
|
assert len(response.data) == 1
|
||||||
|
|
||||||
|
|
||||||
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)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user