From a3df7574f934673d9c77154bb3e69917ebf85e3e Mon Sep 17 00:00:00 2001 From: Tom Forbes Date: Tue, 7 Aug 2018 22:32:29 +0100 Subject: [PATCH] Fixed #29644 -- Made SearchQuery.__str__() reflect negation and grouping. --- django/contrib/postgres/search.py | 7 +++++++ tests/postgres_tests/test_search.py | 28 +++++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/django/contrib/postgres/search.py b/django/contrib/postgres/search.py index 7bda2291a0..63fa9116ec 100644 --- a/django/contrib/postgres/search.py +++ b/django/contrib/postgres/search.py @@ -158,12 +158,19 @@ class SearchQuery(SearchQueryCombinable, Value): def __invert__(self): return type(self)(self.value, config=self.config, invert=not self.invert) + def __str__(self): + result = super().__str__() + return ('~%s' % result) if self.invert else result + class CombinedSearchQuery(SearchQueryCombinable, CombinedExpression): def __init__(self, lhs, connector, rhs, config, output_field=None): self.config = config super().__init__(lhs, connector, rhs, output_field) + def __str__(self): + return '(%s)' % super().__str__() + class SearchRank(Func): function = 'ts_rank' diff --git a/tests/postgres_tests/test_search.py b/tests/postgres_tests/test_search.py index 405de8cf0e..5ab7609cb3 100644 --- a/tests/postgres_tests/test_search.py +++ b/tests/postgres_tests/test_search.py @@ -9,7 +9,7 @@ from django.contrib.postgres.search import ( SearchQuery, SearchRank, SearchVector, ) from django.db.models import F -from django.test import modify_settings +from django.test import SimpleTestCase, modify_settings from . import PostgreSQLTestCase from .models import Character, Line, Scene @@ -292,3 +292,29 @@ class TestRankingAndWeights(GrailTestData, PostgreSQLTestCase): rank=SearchRank(SearchVector('dialogue'), SearchQuery('brave sir robin')), ).filter(rank__gt=0.3) self.assertSequenceEqual(searched, [self.verse0]) + + +class SearchQueryTests(SimpleTestCase): + def test_str(self): + tests = ( + (~SearchQuery('a'), '~SearchQuery(a)'), + ( + (SearchQuery('a') | SearchQuery('b')) & (SearchQuery('c') | SearchQuery('d')), + '((SearchQuery(a) || SearchQuery(b)) && (SearchQuery(c) || SearchQuery(d)))', + ), + ( + SearchQuery('a') & (SearchQuery('b') | SearchQuery('c')), + '(SearchQuery(a) && (SearchQuery(b) || SearchQuery(c)))', + ), + ( + (SearchQuery('a') | SearchQuery('b')) & SearchQuery('c'), + '((SearchQuery(a) || SearchQuery(b)) && SearchQuery(c))' + ), + ( + SearchQuery('a') & (SearchQuery('b') & (SearchQuery('c') | SearchQuery('d'))), + '(SearchQuery(a) && (SearchQuery(b) && (SearchQuery(c) || SearchQuery(d))))', + ), + ) + for query, expected_str in tests: + with self.subTest(query=query): + self.assertEqual(str(query), expected_str)