Skip to content

Commit

Permalink
Fix person sorting
Browse files Browse the repository at this point in the history
1. Same fix as DemocracyClub/WhoCanIVoteFor#1131
2. `sort_name` is NOT NULL so `Coalesce` always returned the sort name
3. Add `NullIfBlank` function to force sort name to return NULL
  • Loading branch information
symroe committed Apr 9, 2022
1 parent 7a59475 commit 134a93d
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 11 deletions.
11 changes: 8 additions & 3 deletions ynr/apps/elections/api/next/api_views.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from typing import OrderedDict
from django.db.models import Prefetch
from django.db.models.functions import Coalesce
from django.utils.decorators import method_decorator
from django.views.decorators.cache import cache_page
from drf_yasg import openapi
Expand All @@ -16,7 +17,7 @@
from elections.models import Election
from official_documents.models import OfficialDocument
from popolo.models import Membership
from utils.db import LastWord
from utils.db import LastWord, NullIfBlank


class ElectionViewSet(viewsets.ReadOnlyModelViewSet):
Expand Down Expand Up @@ -46,12 +47,16 @@ class BallotViewSet(viewsets.ReadOnlyModelViewSet):
queryset=Membership.objects.all()
.select_related("result", "person", "party")
.annotate(last_name=LastWord("person__name"))
.annotate(
name_for_ordering=Coalesce(
NullIfBlank("person__sort_name"), "last_name"
)
)
.order_by(
"-elected",
"-result__num_ballots",
"party_list_position",
"person__sort_name",
"last_name",
"name_for_ordering",
),
),
Prefetch(
Expand Down
10 changes: 8 additions & 2 deletions ynr/apps/popolo/querysets.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

from django.db import models
from django.db.models import Q
from django.db.models.functions import Coalesce

from utils.db import LastWord
from utils.db import LastWord, NullIfBlank

__author__ = "guglielmo"

Expand Down Expand Up @@ -96,10 +97,15 @@ def memberships_for_ballot(
if ballot.election.party_lists_in_use:
order_by += ["party__name", "party_list_position"]
else:
order_by += ["person__sort_name", "last_name"]
order_by += ["name_for_ordering", "person__name"]
qs = self.filter(ballot=ballot)

qs = qs.annotate(last_name=LastWord("person__name"))
qs = qs.annotate(
name_for_ordering=Coalesce(
NullIfBlank("person__sort_name"), "last_name"
)
)
qs = qs.order_by(*order_by)
qs = qs.select_related("person", "person__image", "party", "result")
if ballot.is_welsh_run:
Expand Down
12 changes: 9 additions & 3 deletions ynr/apps/uk_results/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@
from django import forms
from django.core.exceptions import ValidationError
from django.db import transaction
from django.db.models.functions import Coalesce

from candidates.models import LoggedAction
from candidates.models.db import ActionType
from candidates.views.version_data import get_client_ip
from uk_results.helpers import RecordBallotResultsHelper
from utils.db import LastWord
from utils.db import LastWord, NullIfBlank

from .models import CandidateResult, ResultSet

Expand Down Expand Up @@ -52,8 +53,13 @@ def __init__(self, ballot, *args, **kwargs):
fields = OrderedDict()
memberships = (
ballot.membership_set.all()
.annotate(sorted_name=LastWord("person__name"))
.order_by("sorted_name")
.annotate(last_name=LastWord("person__name"))
.annotate(
name_for_ordering=Coalesce(
NullIfBlank("person__sort_name"), "last_name"
)
)
.order_by("name_for_ordering")
)

for membership in memberships:
Expand Down
8 changes: 5 additions & 3 deletions ynr/apps/utils/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@ class LastWord(Transform):

function = "LastWord"
template = """
(regexp_split_to_array(%(field)s, ' '))[
array_upper(regexp_split_to_array(%(field)s, ' '), 1)
]
regexp_replace(%(field)s, '^.* ', '')
"""

def __init__(self, column, output_field=None):
Expand All @@ -20,6 +18,10 @@ def as_postgresql(self, compiler, connection):
return self.as_sql(compiler, connection)


class NullIfBlank(Func):
template = "NULLIF(%(expressions)s, '')"


class Levenshtein(Func):
"""
Uses postgres fuzzystrmatch to determine similarity between
Expand Down

0 comments on commit 134a93d

Please sign in to comment.