kopia lustrzana https://github.com/wagtail/wagtail
rodzic
df9437b4de
commit
66a086da29
|
@ -19,6 +19,7 @@ Changelog
|
|||
* Switch lock/unlock side panel toggle to a switch, with more appropriate confirmation message status (Sage Abdullah)
|
||||
* Ensure that changed or cleared selection from choosers will dispatch a DOM `change` event (George Sakkis)
|
||||
* Add the ability to disable model indexing by setting `search_fields = []` (Daniel Kirkham)
|
||||
* Enhance `wagtail.search.utils.parse_query_string` to allow inner single quotes for key/value parsing (Aman Pandey)
|
||||
* Fix: Ensure `label_format` on StructBlock gracefully handles missing variables (Aadi jindal)
|
||||
* Fix: Adopt a no-JavaScript and more accessible solution for the 'Reset to default' switch to Gravatar when editing user profile (Loveth Omokaro)
|
||||
* Fix: Ensure `Site.get_site_root_paths` works on cache backends that do not preserve Python objects (Jaap Roes)
|
||||
|
|
|
@ -31,6 +31,7 @@ Support for adding custom validation logic to StreamField blocks has been formal
|
|||
* Switch lock/unlock side panel toggle to a switch, with more appropriate confirmation message status (Sage Abdullah)
|
||||
* Ensure that changed or cleared selection from choosers will dispatch a DOM `change` event (George Sakkis)
|
||||
* Add the ability to [disable model indexing](wagtailsearch_disable_indexing) by setting `search_fields = []` (Daniel Kirkham)
|
||||
* Enhance `wagtail.search.utils.parse_query_string` to allow inner single quotes for key/value parsing (Aman Pandey)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
|
|
|
@ -272,11 +272,14 @@ For example:
|
|||
|
||||
```python
|
||||
>>> from wagtail.search.utils import parse_query_string
|
||||
>>> filters, query = parse_query_string('my query string "this is a phrase" this-is-a:filter', operator='and')
|
||||
>>> filters, query = parse_query_string('my query string "this is a phrase" this_is_a:filter', operator='and')
|
||||
|
||||
# Alternatively..
|
||||
# filters, query = parse_query_string("my query string 'this is a phrase' this_is_a:filter", operator='and')
|
||||
|
||||
>>> filters
|
||||
{
|
||||
'this-is-a': 'filter',
|
||||
'this_is_a': 'filter',
|
||||
}
|
||||
|
||||
>>> query
|
||||
|
|
|
@ -235,6 +235,13 @@ class TestSeparateFiltersFromQuery(SimpleTestCase):
|
|||
self.assertDictEqual(filters, {"author": "foo bar", "bar": "two beers"})
|
||||
self.assertEqual(query, "hello world")
|
||||
|
||||
filters, query = separate_filters_from_query(
|
||||
"author:'foo bar' hello world bar:'two beers'"
|
||||
)
|
||||
|
||||
self.assertDictEqual(filters, {"author": "foo bar", "bar": "two beers"})
|
||||
self.assertEqual(query, "hello world")
|
||||
|
||||
|
||||
class TestParseQueryString(SimpleTestCase):
|
||||
def test_simple_query(self):
|
||||
|
@ -249,6 +256,11 @@ class TestParseQueryString(SimpleTestCase):
|
|||
self.assertDictEqual(filters, {})
|
||||
self.assertEqual(repr(query), repr(Phrase("hello world")))
|
||||
|
||||
filters, query = parse_query_string("'hello world'")
|
||||
|
||||
self.assertDictEqual(filters, {})
|
||||
self.assertEqual(repr(query), repr(Phrase("hello world")))
|
||||
|
||||
def test_with_simple_and_phrase(self):
|
||||
filters, query = parse_query_string('this is simple "hello world"')
|
||||
|
||||
|
@ -257,6 +269,13 @@ class TestParseQueryString(SimpleTestCase):
|
|||
repr(query), repr(And([PlainText("this is simple"), Phrase("hello world")]))
|
||||
)
|
||||
|
||||
filters, query = parse_query_string("this is simple 'hello world'")
|
||||
|
||||
self.assertDictEqual(filters, {})
|
||||
self.assertEqual(
|
||||
repr(query), repr(And([PlainText("this is simple"), Phrase("hello world")]))
|
||||
)
|
||||
|
||||
def test_operator(self):
|
||||
filters, query = parse_query_string(
|
||||
'this is simple "hello world"', operator="or"
|
||||
|
@ -270,18 +289,40 @@ class TestParseQueryString(SimpleTestCase):
|
|||
),
|
||||
)
|
||||
|
||||
filters, query = parse_query_string(
|
||||
"this is simple 'hello world'", operator="or"
|
||||
)
|
||||
|
||||
self.assertDictEqual(filters, {})
|
||||
self.assertEqual(
|
||||
repr(query),
|
||||
repr(
|
||||
Or([PlainText("this is simple", operator="or"), Phrase("hello world")])
|
||||
),
|
||||
)
|
||||
|
||||
def test_with_phrase_unclosed(self):
|
||||
filters, query = parse_query_string('"hello world')
|
||||
|
||||
self.assertDictEqual(filters, {})
|
||||
self.assertEqual(repr(query), repr(Phrase("hello world")))
|
||||
|
||||
filters, query = parse_query_string("'hello world")
|
||||
|
||||
self.assertDictEqual(filters, {})
|
||||
self.assertEqual(repr(query), repr(Phrase("hello world")))
|
||||
|
||||
def test_phrase_with_filter(self):
|
||||
filters, query = parse_query_string('"hello world" author:"foo bar" bar:beer')
|
||||
|
||||
self.assertDictEqual(filters, {"author": "foo bar", "bar": "beer"})
|
||||
self.assertEqual(repr(query), repr(Phrase("hello world")))
|
||||
|
||||
filters, query = parse_query_string("'hello world' author:'foo bar' bar:beer")
|
||||
|
||||
self.assertDictEqual(filters, {"author": "foo bar", "bar": "beer"})
|
||||
self.assertEqual(repr(query), repr(Phrase("hello world")))
|
||||
|
||||
def test_multiple_phrases(self):
|
||||
filters, query = parse_query_string('"hello world" "hi earth"')
|
||||
|
||||
|
@ -289,6 +330,23 @@ class TestParseQueryString(SimpleTestCase):
|
|||
repr(query), repr(And([Phrase("hello world"), Phrase("hi earth")]))
|
||||
)
|
||||
|
||||
filters, query = parse_query_string("'hello world' 'hi earth'")
|
||||
|
||||
self.assertEqual(
|
||||
repr(query), repr(And([Phrase("hello world"), Phrase("hi earth")]))
|
||||
)
|
||||
|
||||
def test_mixed_phrases_with_filters(self):
|
||||
filters, query = parse_query_string(
|
||||
""""lord of the rings" army_1:"elves" army_2:'humans'"""
|
||||
)
|
||||
|
||||
self.assertDictEqual(filters, {"army_1": "elves", "army_2": "humans"})
|
||||
self.assertEqual(
|
||||
repr(query),
|
||||
repr(Phrase("lord of the rings")),
|
||||
)
|
||||
|
||||
|
||||
class TestBalancedReduce(SimpleTestCase):
|
||||
# For simple values, this should behave exactly the same as Pythons reduce()
|
||||
|
|
|
@ -82,12 +82,14 @@ def normalise_query_string(query_string):
|
|||
|
||||
|
||||
def separate_filters_from_query(query_string):
|
||||
filters_regexp = r'(\w+):(\w+|"[^"]+")'
|
||||
filters_regexp = r'(\w+):(\w+|"[^"]+"|\'[^\']+\')'
|
||||
|
||||
filters = {}
|
||||
for match_object in re.finditer(filters_regexp, query_string):
|
||||
key, value = match_object.groups()
|
||||
filters[key] = value.strip('"')
|
||||
filters[key] = (
|
||||
value.strip('"') if value.strip('"') is not value else value.strip("'")
|
||||
)
|
||||
|
||||
query_string = re.sub(filters_regexp, "", query_string).strip()
|
||||
|
||||
|
@ -112,7 +114,12 @@ def parse_query_string(query_string, operator=None, zero_terms=MATCH_NONE):
|
|||
|
||||
is_phrase = False
|
||||
tokens = []
|
||||
for part in query_string.split('"'):
|
||||
if '"' in query_string:
|
||||
parts = query_string.split('"')
|
||||
else:
|
||||
parts = query_string.split("'")
|
||||
|
||||
for part in parts:
|
||||
part = part.strip()
|
||||
|
||||
if part:
|
||||
|
|
Ładowanie…
Reference in New Issue