mirror of
				https://github.com/encode/django-rest-framework.git
				synced 2025-10-31 07:57:55 +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