fix: give priority to small usernames when query is small

Basically, when the search is "joe" we first try to search for
an exact account named "joe", and fallback to normal flow when
nothing matches.

fix #2591
This commit is contained in:
Yohan Boniface 2025-04-07 15:24:44 +02:00
parent 190cac3105
commit f4ae51ae7e
2 changed files with 37 additions and 0 deletions

View file

@ -2,6 +2,7 @@ from agnocomplete.core import AgnocompleteModel
from agnocomplete.register import register from agnocomplete.register import register
from django.conf import settings from django.conf import settings
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.db.models import Q
@register @register
@ -13,3 +14,24 @@ class AutocompleteUser(AgnocompleteModel):
data = super().item(current_item) data = super().item(current_item)
data["url"] = current_item.get_url() data["url"] = current_item.get_url()
return data return data
def get_queryset_filters(self, query):
if len(query) <= 3 and self._force_exact:
conditions = Q()
for field_name in self.fields:
if not field_name[0].isalnum():
field_name = field_name[1:]
# Force exact match
conditions |= Q(**{self._construct_qs_filter(f"={field_name}"): query})
return conditions
return super().get_queryset_filters(query)
def build_filtered_queryset(self, query, **kwargs):
self._force_exact = len(query) <= 3
qs = super().build_filtered_queryset(query, **kwargs)
if len(query) <= 3 and not len(qs):
# Not exact match, let's fallback to normal "startswith" query
self._force_exact = False
qs = super().build_filtered_queryset(query, **kwargs)
return qs

View file

@ -510,3 +510,18 @@ def test_can_combine_search_and_filter(client, map):
url = reverse("search") url = reverse("search")
response = client.get(url + "?q=dur&tags=bike") response = client.get(url + "?q=dur&tags=bike")
assert "Blé dur" in response.content.decode() assert "Blé dur" in response.content.decode()
@pytest.mark.django_db
def test_can_find_small_usernames(client):
UserFactory(username="Joe")
UserFactory(username="JoeJoe")
url = "/agnocomplete/AutocompleteUser/"
response = client.get(url + "?q=joe")
data = json.loads(response.content)["data"]
assert len(data) == 1
assert data[0]["label"] == "Joe"
response = client.get(url + "?q=joej")
data = json.loads(response.content)["data"]
assert len(data) == 1
assert data[0]["label"] == "JoeJoe"