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