Django группирует по подстроке в поле

У меня есть проект Django, PostgreSQL. Я хочу выполнить группировку по подстроке из поля. Например, у меня есть модель Model1 и ее столбец name. Значение в столбце может быть таким:

ABC-w-JAIPUR-123
XYZ-x-JAIPUR-236
MNO-y-SURAT-23
DEF-q-SURAT-23

Из приведенных выше значений в поле name я хочу сгруппировать по второму вхождению - и окончанию - в нашем случае это будут: "JAIPUR", "SURAT"

Пожалуйста, сообщите мне, как достичь этого в Django.

ОБНОВЛЕНИЕ: На данный момент я попробовал:

Model1.objects.annotate(substring=Substr('name', F('name').index('-')+1, (F('name', output_field=CharField())[:F('name').rindex('-')]).index('-'))).values('substring').annotate(count=Count('id'))

но это дает ошибку:

AttributeError: 'F' object has no attribute 'index'

Ну, F объект [Django-doc] - это просто объект для ссылки на колонку. Он не является строковым значением этого столбца, поэтому вы не можете вызвать .index(…) на нем, например.

Но еще более плохая новость заключается в том, что его эквивалент, StrIndex [Django-doc] не может легко определить второй индекс, поэтому нам придется исправить и это. Однако мы можем исправить это, разрезав строку дважды, и таким образом работать с:

from django.db.models import F, Value
from django.db.models.functions import Left, Length, Right, StrIndex

hyp = Value('-')
drop1 = Right('name', Length('name') - StrIndex('name', hyp))
drop2 = Right(drop1, Length(drop1) - StrIndex(drop1, hyp))
drop3 = Left(drop2, StrIndex(drop2, hyp) - 1)

Тогда мы можем, например, аннотировать так:

Model1.objects.annotate(foo=drop3)

Таким образом, drop1 отбросит ABC-, второй drop2 отбросит w- и, наконец, drop3 отбросит все остальные группы, так что вместо них вернется JAIPUR.

При этом, пожалуйста, не делайте поля, которые каким-то образом группируют данные вместе. Храните различные элементы в разных столбцах. Объединять данные зачастую намного проще, чем извлекать.

Вернуться на верх