[Postgres_search] Adds a default ordering when ranking of objects is the same.

pull/3788/head
Bertrand Bordage 2017-08-21 15:07:13 +02:00 zatwierdzone przez Matt Westcott
rodzic 5278e005a0
commit 894887e7da
4 zmienionych plików z 31 dodań i 3 usunięć

Wyświetl plik

@ -8,6 +8,8 @@ Changelog
* Fix: Using `order_by_relevance=False` when searching with PostgreSQL now works (Mitchel Cabuloy)
* Fix: Inline panel first and last sorting arrows correctly hidden in non-default tabs (Matt Westcott)
* Fix: `WAGTAILAPI_LIMIT_MAX` now accepts None to disable limiting (jcronyn)
* Fix: In PostgreSQL, new default ordering when ranking of objects is the same (Bertrand Bordage)
1.12 LTS (21.08.2017)
~~~~~~~~~~~~~~~~~~~~~

Wyświetl plik

@ -22,6 +22,7 @@ Bug fixes
* Using ``order_by_relevance=False`` when searching with PostgreSQL now works (Mitchel Cabuloy)
* Inline panel first and last sorting arrows correctly hidden in non-default tabs (Matt Westcott)
* ``WAGTAILAPI_LIMIT_MAX`` now accepts None to disable limiting (jcronyn)
* In PostgreSQL, new default ordering when ranking of objects is the same (Bertrand Bordage)
Upgrade considerations

Wyświetl plik

@ -246,12 +246,13 @@ class PostgresSearchQuery(BaseSearchQuery):
def search_in_index(self, queryset, search_query, start, stop):
index_entries = self.get_in_index_queryset(queryset, search_query)
order_sql = ''
values = ['typed_pk']
if self.order_by_relevance:
index_entries = index_entries.rank(search_query)
values.append('rank')
order_sql = 'ORDER BY index_entry.rank DESC'
order_sql = 'index_entry.rank DESC, id ASC'
else:
order_sql = 'id ASC'
index_sql, index_params = get_sql(
index_entries.annotate_typed_pk()
.values(*values)
@ -262,7 +263,7 @@ class PostgresSearchQuery(BaseSearchQuery):
SELECT obj.*
FROM (%s) AS index_entry
INNER JOIN (%s) AS obj ON obj."%s" = index_entry.typed_pk
%s
ORDER BY %s
OFFSET %%s LIMIT %%s;
""" % (index_sql, model_sql, get_pk_column(model), order_sql)
limits = (start, None if stop is None else stop - start)

Wyświetl plik

@ -200,6 +200,30 @@ class BackendTests(WagtailTestUtils):
set(unsorted_results),
{self.testa, self.testb, self.testc.searchtest_ptr})
def test_same_rank_pages(self):
"""
Checks that results with a same ranking cannot be found multiple times
across pages (see issue #3729).
"""
same_rank_objects = set()
try:
for i in range(10):
obj = models.SearchTest.objects.create(title='Rank %s' % i)
self.backend.add(obj)
same_rank_objects.add(obj)
self.refresh_index()
results = self.backend.search('Rank', models.SearchTest)
results_across_pages = set()
for i, obj in enumerate(same_rank_objects):
results_across_pages.add(results[i:i + 1][0])
self.assertSetEqual(results_across_pages, same_rank_objects)
finally:
for obj in same_rank_objects:
self.backend.delete(obj)
obj.delete()
self.refresh_index()
def test_delete(self):
# Delete one of the objects
self.backend.delete(self.testa)