mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-07-18 04:02:35 +03:00
Allow search to split also by comma after smart split
This commit is contained in:
parent
82c42dc5db
commit
1ce85d01b5
|
@ -20,6 +20,21 @@ from rest_framework.fields import CharField
|
||||||
from rest_framework.settings import api_settings
|
from rest_framework.settings import api_settings
|
||||||
|
|
||||||
|
|
||||||
|
def search_smart_split(search_terms):
|
||||||
|
"""generator that first splits string by spaces, leaving quoted phrases togheter,
|
||||||
|
then it splits non-quoted phrases by commas.
|
||||||
|
"""
|
||||||
|
for term in smart_split(search_terms):
|
||||||
|
# trim commas to avoid bad matching for quoted phrases
|
||||||
|
term = term.strip(',')
|
||||||
|
if term.startswith(('"', "'")) and term[0] == term[-1]:
|
||||||
|
# quoted phrases are kept togheter without any other split
|
||||||
|
yield unescape_string_literal(term)
|
||||||
|
else:
|
||||||
|
# non-quoted tokens are split by comma, keeping only non-empty ones
|
||||||
|
yield from (sub_term.strip() for sub_term in term.split(',') if sub_term)
|
||||||
|
|
||||||
|
|
||||||
class BaseFilterBackend:
|
class BaseFilterBackend:
|
||||||
"""
|
"""
|
||||||
A base class from which all filter backend classes should inherit.
|
A base class from which all filter backend classes should inherit.
|
||||||
|
@ -144,9 +159,7 @@ class SearchFilter(BaseFilterBackend):
|
||||||
|
|
||||||
base = queryset
|
base = queryset
|
||||||
conditions = []
|
conditions = []
|
||||||
for term in smart_split(search_terms):
|
for term in search_smart_split(search_terms):
|
||||||
if term.startswith(('"', "'")) and term[0] == term[-1]:
|
|
||||||
term = unescape_string_literal(term)
|
|
||||||
queries = [
|
queries = [
|
||||||
models.Q(**{orm_lookup: term})
|
models.Q(**{orm_lookup: term})
|
||||||
for orm_lookup in orm_lookups
|
for orm_lookup in orm_lookups
|
||||||
|
|
|
@ -6,7 +6,7 @@ from django.core.exceptions import ImproperlyConfigured
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models import CharField, Transform
|
from django.db.models import CharField, Transform
|
||||||
from django.db.models.functions import Concat, Upper
|
from django.db.models.functions import Concat, Upper
|
||||||
from django.test import TestCase
|
from django.test import SimpleTestCase, TestCase
|
||||||
from django.test.utils import override_settings
|
from django.test.utils import override_settings
|
||||||
|
|
||||||
from rest_framework import filters, generics, serializers
|
from rest_framework import filters, generics, serializers
|
||||||
|
@ -17,6 +17,25 @@ from rest_framework.test import APIRequestFactory
|
||||||
factory = APIRequestFactory()
|
factory = APIRequestFactory()
|
||||||
|
|
||||||
|
|
||||||
|
class SearchSplitTests(SimpleTestCase):
|
||||||
|
|
||||||
|
def test_keep_quoted_togheter_regardless_of_commas(self):
|
||||||
|
assert ['hello, world'] == list(filters.search_smart_split('"hello, world"'))
|
||||||
|
|
||||||
|
def test_strips_commas_around_quoted(self):
|
||||||
|
assert ['hello, world'] == list(filters.search_smart_split(',,"hello, world"'))
|
||||||
|
assert ['hello, world'] == list(filters.search_smart_split(',,"hello, world",,'))
|
||||||
|
assert ['hello, world'] == list(filters.search_smart_split('"hello, world",,'))
|
||||||
|
|
||||||
|
def test_splits_by_comma(self):
|
||||||
|
assert ['hello', 'world'] == list(filters.search_smart_split(',,hello, world'))
|
||||||
|
assert ['hello', 'world'] == list(filters.search_smart_split(',,hello, world,,'))
|
||||||
|
assert ['hello', 'world'] == list(filters.search_smart_split('hello, world,,'))
|
||||||
|
|
||||||
|
def test_splits_quotes_followed_by_comma_and_sentence(self):
|
||||||
|
assert ['"hello', 'world"', 'found'] == list(filters.search_smart_split('"hello, world",found'))
|
||||||
|
|
||||||
|
|
||||||
class BaseFilterTests(TestCase):
|
class BaseFilterTests(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.original_coreapi = filters.coreapi
|
self.original_coreapi = filters.coreapi
|
||||||
|
@ -435,7 +454,7 @@ class SearchFilterToManyTests(TestCase):
|
||||||
search_fields = ('=name', 'entry__headline', '=entry__pub_date__year')
|
search_fields = ('=name', 'entry__headline', '=entry__pub_date__year')
|
||||||
|
|
||||||
view = SearchListView.as_view()
|
view = SearchListView.as_view()
|
||||||
request = factory.get('/', {'search': 'Lennon 1979'})
|
request = factory.get('/', {'search': 'Lennon,1979'})
|
||||||
response = view(request)
|
response = view(request)
|
||||||
assert len(response.data) == 1
|
assert len(response.data) == 1
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user