diff --git a/itou/users/migrations/0023_remove_user_full_name_search_idx_and_more.py b/itou/users/migrations/0023_remove_user_full_name_search_idx_and_more.py new file mode 100644 index 0000000000..a47d4efc0f --- /dev/null +++ b/itou/users/migrations/0023_remove_user_full_name_search_idx_and_more.py @@ -0,0 +1,36 @@ +# Generated by Django 5.1.4 on 2025-01-10 14:48 + +import django.contrib.postgres.indexes +import django.contrib.postgres.lookups +import django.contrib.postgres.search +from django.db import migrations + + +class Migration(migrations.Migration): + dependencies = [ + ("auth", "0012_alter_user_first_name_max_length"), + ("cities", "0001_initial"), + ("users", "0022_user_full_name_search_idx"), + ] + + operations = [ + migrations.RemoveIndex( + model_name="user", + name="full_name_search_idx", + ), + migrations.RemoveField( + model_name="user", + name="full_name", + ), + migrations.AddIndex( + model_name="user", + index=django.contrib.postgres.indexes.GinIndex( + django.contrib.postgres.search.SearchVector( + django.contrib.postgres.lookups.Unaccent("first_name"), + django.contrib.postgres.lookups.Unaccent("last_name"), + config="simple", + ), + name="full_name_search_idx", + ), + ), + ] diff --git a/itou/users/models.py b/itou/users/models.py index 404bf03b6a..7e07cc4c9c 100644 --- a/itou/users/models.py +++ b/itou/users/models.py @@ -9,7 +9,7 @@ from django.contrib.auth.models import AbstractUser, UserManager from django.contrib.postgres.indexes import GinIndex, OpClass from django.contrib.postgres.lookups import Unaccent -from django.contrib.postgres.search import SearchVector, SearchVectorField +from django.contrib.postgres.search import SearchVector from django.core.exceptions import ValidationError from django.core.serializers.json import DjangoJSONEncoder from django.core.validators import MaxLengthValidator, MinLengthValidator, RegexValidator @@ -172,12 +172,6 @@ class User(AbstractUser, AddressMixin): default="", choices=Title.choices, ) - full_name = models.GeneratedField( - expression=SearchVector(Unaccent("first_name"), Unaccent("last_name"), config="simple"), - output_field=SearchVectorField(), - verbose_name="nom complet utilisé pour rechercher un utilisateur", - db_persist=True, - ) email = CIEmailField( "adresse e-mail", @@ -240,7 +234,10 @@ class Meta(AbstractUser.Meta): OpClass(Upper("email"), name="text_pattern_ops"), name="users_user_email_upper", ), - GinIndex("full_name", name="full_name_search_idx"), + GinIndex( + SearchVector(Unaccent("first_name"), Unaccent("last_name"), config="simple"), + name="full_name_search_idx", + ), ] constraints = [ models.CheckConstraint( diff --git a/itou/www/autocomplete/views.py b/itou/www/autocomplete/views.py index f78aec7695..2d99267c7c 100644 --- a/itou/www/autocomplete/views.py +++ b/itou/www/autocomplete/views.py @@ -1,7 +1,8 @@ from datetime import datetime from django.contrib.auth.decorators import login_not_required -from django.contrib.postgres.search import SearchQuery, SearchRank +from django.contrib.postgres.lookups import Unaccent +from django.contrib.postgres.search import SearchQuery, SearchRank, SearchVector from django.db.models import Exists, F, OuterRef, Q, Value from django.db.models.functions import Least, Lower, NullIf, StrIndex from django.http import JsonResponse @@ -155,6 +156,9 @@ def gps_users_autocomplete(request): ) search_query = SearchQuery(unidecode(term), config="simple") + users_qs = users_qs.annotate( + full_name=SearchVector(Unaccent("first_name"), Unaccent("last_name"), config="simple") + ) users_qs = users_qs.filter(full_name=search_query) users_qs = users_qs.annotate(rank=SearchRank("full_name", search_query)).order_by("-rank")