Use Django full text instead of custom SQL

This commit is contained in:
Yohan Boniface 2023-05-11 11:33:08 +02:00
parent 005a759b81
commit 1038836a72
5 changed files with 27 additions and 14 deletions

View file

@ -82,8 +82,15 @@ Start the server
UMap uses PostgreSQL tsvector for searching. In case your database is big, you
may want to add an index. For that, you should do so:
# Create a basic search configuration
CREATE TEXT SEARCH CONFIGURATION umapdict (COPY=simple);
# If you also want to deal with accents and case, add this before creating the index
CREATE EXTENSION unaccent;
CREATE EXTENSION btree_gin;
CREATE TEXT SEARCH CONFIGURATION umapdict (COPY=simple);
ALTER TEXT SEARCH CONFIGURATION umapdict ALTER MAPPING FOR hword, hword_part, word WITH unaccent, simple;
# Now create the index
CREATE INDEX IF NOT EXISTS search_idx ON umap_map USING GIN(to_tsvector('umapdict', name), share_status);
And change `UMAP_SEARCH_CONFIGURATION = "umapdict"` in your settings.

View file

@ -215,7 +215,7 @@ UMAP_DEMO_SITE = False
UMAP_EXCLUDE_DEFAULT_MAPS = False
UMAP_MAPS_PER_PAGE = 5
UMAP_MAPS_PER_PAGE_OWNER = 10
UMAP_USE_UNACCENT = False
UMAP_SEARCH_CONFIGURATION = "simple"
UMAP_FEEDBACK_LINK = "https://wiki.openstreetmap.org/wiki/UMap#Feedback_and_help" # noqa
USER_MAPS_URL = 'user_maps'
DATABASES = {

View file

@ -94,11 +94,6 @@ SHORT_SITE_URL = "http://s.hort"
# POSTGIS_VERSION = (2, 1, 0)
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
# You need to unable accent extension before using UMAP_USE_UNACCENT
# python manage.py dbshell
# CREATE EXTENSION unaccent;
UMAP_USE_UNACCENT = False
# Put the site in readonly mode (useful for migration or any maintenance)
UMAP_READONLY = False

View file

@ -529,3 +529,13 @@ def test_create_readonly(client, user, post_data, settings):
response = client.post(url, post_data)
assert response.status_code == 403
assert response.content == b'Site is readonly for maintenance'
def test_search(client, map):
# Very basic search, that do not deal with accent nor case.
# See install.md for how to have a smarter dict + index.
map.name = "Blé dur"
map.save()
url = reverse("search")
response = client.get(url + "?q=Blé")
assert "Blé dur" in response.content.decode()

View file

@ -10,6 +10,7 @@ from django.contrib import messages
from django.contrib.auth import logout as do_logout
from django.contrib.auth import get_user_model
from django.contrib.gis.measure import D
from django.contrib.postgres.search import SearchQuery, SearchRank, SearchVector
from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator
from django.core.signing import BadSignature, Signer
from django.core.validators import URLValidator, ValidationError
@ -190,13 +191,13 @@ class Search(TemplateView, PaginatorMixin):
q = self.request.GET.get("q")
results = []
if q:
where = "to_tsvector(name) @@ websearch_to_tsquery(%s)"
if getattr(settings, "UMAP_USE_UNACCENT", False):
where = "to_tsvector('umapdict',name) @@ websearch_to_tsquery('umapdict',%s)" # noqa
results = Map.objects.filter(share_status=Map.PUBLIC)
results = results.extra(where=[where], params=[q])
results = results.order_by("-modified_at")
results = self.paginate(results)
vector = SearchVector("name", config=settings.UMAP_SEARCH_CONFIGURATION)
query = SearchQuery(
q, config=settings.UMAP_SEARCH_CONFIGURATION, search_type="websearch"
)
qs = Map.objects.annotate(search=vector).filter(search=query)
qs = qs.filter(share_status=Map.PUBLIC).order_by('-modified_at')
results = self.paginate(qs)
kwargs.update({"maps": results, "q": q})
return kwargs