[Django]-The `length` and `name` sort params do not meet my requirement

2👍

You’ll need to extract the numbers from the strings. Postgres and mysql provide regexp_replace function (I’m not sure about other databases). But Django doesn’t provide an implementation, so we’ll write our own function:

from django.db.models import Func, Value

class RegexpReplace(Func):
    function = 'REGEXP_REPLACE'

    def __init__(self, expression, search, replace, **extra):
        search = Value(search)
        replace = Value(replace)
        super(RegexpReplace, self).__init__(expression, search, replace, **extra)

I’ll assume you want to split the names until the digits at the end, and then you want to sort using this first half, and then the numbers at the end. (This will work fine for you until you start getting 3-digit numbers before the hyphen, i.e. SE99-A1, SE100-A1).

from django.db.models import F, IntegerField
from django.db.models.functions import Cast

qs = ... # get your queryset
qs.annotate(
    letters=RegexpReplace(F('name'), '(.*[a-zA-Z])[0-9]+$', r'\1'),
    seq=Cast(
        RegexpReplace(F('name'), '.*[a-zA-Z]([0-9]+)$', r'\1'),
        IntegerField(),
    ),
).order_by('letters', 'seq')

0👍

Use Substr to separate out the first part of the name from the numbers at the end, and then sort by this new annotation first.

from django.db.models.functions import Substr, Length

qs = qs.annotate(letters=Substr('name', 1, 6), length=Length('name'))
qs = qs.order_by('letters', 'length', 'name')
return qs

Leave a comment