Sort objects by a substring of a model field in django

Question:

Im trying to find best solution to sort through all Machine objects in my db and find last deviceSerialNo used.

deviceSerialNo is a character field and has a structure like this: AB12-12344.

My task is to sort all Machine objects by a substring of deviceSerialNo field(everything after ‘-‘ in deviceSerialNo.
My current solution that kind of works

last = Machine.objects.all().order_by('-deviceSerialNo').first().deviceSerialNo

or

last2 = Machine.objects.all().order_by('-deviceSerialNo').annotate(search_index=StrIndex('deviceSerialNo', V('-'))).first().deviceSerialNo

Can someone help me sort it as I mentioned above?

Asked By: pawisoon

||

Answers:

You can order by a field created with annotate:

from django.db.models import IntegerField, Value as V
from django.db.models.functions import Cast, StrIndex, Substr

last = (
    Machine.objects.annotate(
        part=Cast(Substr("deviceSerialNo", StrIndex("deviceSerialNo", V("-"))), IntegerField())
    )
    .order_by("part")
    .first()
    .deviceSerialNo
)

Just like you had we start by getting the index of the - character:

StrIndex('deviceSerialNo', V('-'))

We then take use Substr to get the second part including the - character:

Substr("deviceSerialNo", StrIndex("deviceSerialNo", V("-")))

Then we cast it to an IntegerField, sort and get the first object. Note: We can get the first object as the integer cast of "-12344" is a negative number.

Answered By: ikkuh

If number have multiple – and want to extract out number from reverse then try following. AB-12-12344

Output: 12344

qs.annotate(
   r_part=Reverse('number')
).annotate(
   part=Reverse(
        Cast(
             Substr("r_part", 1, StrIndex("r_part", V("-")))
        ), 
        IntegerField()
    )

)

thanks

Answered By: Naresh Chaudhary

You can sort the objects using the extra() function:

your_objects = Machine.objects.all()
your_objects = your_objects.extra(select={‘str_deviceSerialNo’:’SUBSTRING("deviceSerialNo",initial_char,last_char)’}).order_by(‘str_deviceSerialNo’)

It worked for me.

Answered By: SancheZ85
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.