From f566f594f446741a8b1c29ef10f522b186f66f20 Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Tue, 26 Jan 2021 09:08:33 +0100 Subject: [PATCH] api_views: order users as in the model (#49899) --- src/authentic2/api_views.py | 11 +++++++++-- src/authentic2/custom_user/managers.py | 15 +++++++++------ 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/authentic2/api_views.py b/src/authentic2/api_views.py index 66c9d16a..a4a6f356 100644 --- a/src/authentic2/api_views.py +++ b/src/authentic2/api_views.py @@ -66,6 +66,7 @@ from . import (utils, decorators, attribute_kinds, app_settings, hooks, from .models import Attribute, PasswordReset, Service from .a2_rbac.utils import get_default_ou from .journal_event_types import UserLogin, UserRegistration +from .utils.lookups import Unaccent # Retro-compatibility with older Django versions @@ -384,6 +385,7 @@ class BaseUserSerializer(serializers.ModelSerializer): required=False, default=get_default_ou) date_joined = serializers.DateTimeField(read_only=True) last_login = serializers.DateTimeField(read_only=True) + dist = serializers.FloatField(read_only=True) send_registration_email = serializers.BooleanField(write_only=True, required=False, default=False) send_registration_email_next_url = serializers.URLField(write_only=True, required=False) @@ -747,9 +749,14 @@ class UsersAPI(api_mixins.GetOrCreateMixinView, HookMixin, ExceptionHandlerMixin # https://django-filter.readthedocs.io/en/master/guide/migration.html filter_class = UsersFilter filterset_class = UsersFilter - filter_backends = api_settings.DEFAULT_FILTER_BACKENDS + [FreeTextSearchFilter] + filter_backends = [FreeTextSearchFilter] + api_settings.DEFAULT_FILTER_BACKENDS pagination_class = pagination.CursorPagination - ordering = ['modified', 'id'] + + @property + def ordering(self): + if 'q' in self.request.GET: + return ['dist', Unaccent('last_name'), Unaccent('first_name')] + return User._meta.ordering def get_queryset(self): User = get_user_model() diff --git a/src/authentic2/custom_user/managers.py b/src/authentic2/custom_user/managers.py index 6e97965f..c1587253 100644 --- a/src/authentic2/custom_user/managers.py +++ b/src/authentic2/custom_user/managers.py @@ -40,20 +40,23 @@ class UserQuerySet(models.QuerySet): def free_text_search(self, search): search = search.strip() + def wrap_qs(qs): + return qs.annotate(dist=Value(0, output_field=FloatField())) + if len(search) == 0: - return self.none() + return wrap_qs(self.none()) if '@' in search and len(search.split()) == 1: qs = self.filter(email__iexact=search).order_by('last_name', 'first_name') if qs.exists(): - return qs + return wrap_qs(qs) try: guid = uuid.UUID(search) except ValueError: pass else: - return self.filter(uuid=guid.hex) + return wrap_qs(self.filter(uuid=guid.hex)) try: phone_number = clean_number(search) @@ -64,7 +67,7 @@ class UserQuerySet(models.QuerySet): search_vector=SearchQuery(phone_number), attribute__kind='phone_number') qs = self.filter(attribute_values__in=attribute_values).order_by('last_name', 'first_name') if qs.exists(): - return qs + return wrap_qs(qs) try: date = parse_date(search) @@ -75,7 +78,7 @@ class UserQuerySet(models.QuerySet): search_vector=SearchQuery(date.isoformat()), attribute__kind='birthdate') qs = self.filter(attribute_values__in=attribute_values).order_by('last_name', 'first_name') if qs.exists(): - return qs + return wrap_qs(qs) qs = self.find_duplicates(fullname=search, limit=None, threshold=0.2) extra_user_ids = set() @@ -89,7 +92,7 @@ class UserQuerySet(models.QuerySet): ).values_list('id', flat=True)) if extra_user_ids: qs = qs | self.filter(id__in=extra_user_ids) - qs = qs.order_by('dist', 'last_name', 'first_name') + qs = qs.order_by('dist', Unaccent('last_name'), Unaccent('first_name')) return qs def find_duplicates(self, first_name=None, last_name=None, fullname=None, birthdate=None, limit=5, threshold=None): -- 2.29.2