@ Arakkl_Abu ответ правильный. Я немного поиграл и попытался перестроить ваш метод python с помощью функций базы данных. Это может быть что-то похожее на это:
#admin.py
from django.db.models import Case, Value, When, IntegerField, FloatField, F
from django.db.models.functions import Substr, StrIndex, Cast, Replace, Length
class YelpCompanyAdmin(admin.ModelAdmin):
list_display = ('title','url','messaged','city','annual_revenue','not_available', 'show_annual_revenue1')
def get_queryset(self, request):
qs = YelpCompany.objects.filter(messaged=False,not_available=False).annotate(
field_case=Case(
When(annual_revenue__contains="less than", then=Value(1)),
When(annual_revenue__contains="million", then=Value(2)),
When(annual_revenue__iregex=r'^[a-zA-Z]+/$', then=Value(3)),
When(annual_revenue=None, then=Value(3)),
When(annual_revenue=r'^[/w]+/$', then=Value(3)),
default=Value(4),
output_field=IntegerField()
)
).annotate(
index_nr=Case(
When(field_case=1, then=StrIndex('annual_revenue', Value('less than')) + Length(Value('less than'))),
When(field_case=2, then=StrIndex('annual_revenue', Value('up to')) + Length(Value('up to'))),
When(field_case=3, then=Value(0)),
default=Value(-1),
output_field=IntegerField()
)
).annotate(
annual_revenue1=Case(
When(index_nr__gt=0, then=Cast(Replace(
Substr(F('annual_revenue'), F("index_nr")), Value('$'), Value('')),
output_field=FloatField())),
When(index_nr=0, then=Value(0)),
default=Cast(F('annual_revenue'), output_field=FloatField())
)
)
return qs
def show_annual_revenue1(self, inst):
return inst.annual_revenue1
show_annual_revenue1.admin_order_field = 'annual_revenue1'
Аннотации создают новую аннотацию annual_revenue1
, содержащую только цифру c значения year_revenue. Это можно использовать для заказа. У ModelAdmin
выше есть новый столбец на экране списка, который называется show_annual_revenue1
, который используется для упорядочивания по умолчанию.
Пост, посвященный использованию аннотаций для упорядочения, равен здесь .
Несколько слов объяснения:
Первая аннотация 'Case' сортирует записи 'year_revenue' по группам: 1. Поле содержит «меньше чем», 2. Поле содержит «миллион», 3. Поле содержит буквы, None или пусто, 4. Если ничего из вышеперечисленного не применимо, предполагается, что поле содержит значение цифры c. Возможно, вам придется адаптировать его к вашему особому варианту использования, если применяются другие варианты.
Во второй аннотации 'Case' мы находим индекс для извлечения подстроки, аналогично вашей команде split()
. Поля, которые не содержат действительного значения цифр c, определенного в первой аннотации Case, или значения чисел c помечены index_nr '0' или '-1'.
В третьей аннотации В блоке мы извлекаем подстроку Numberri c или просто возвращаем 0 (если поле не содержит действительного значения NUMERI c) или возвращаем значение поля, если оно может использоваться как есть. Возвращенные значения приводятся к значениям нумерации c, поэтому мы получаем правильную сортировку.
Подход 2
Недостаток подхода, приведенного выше, заключается в том, что он не очень гибкий и довольно "лонги sh". Другим подходом может быть удаление всех строк в начале:
#admin.py
from django.db.models import Case, Value, When, F, FloatField
from django.db.models.functions import Cast, Replace
#admin.py
from django.db.models import Case, Value, When, IntegerField, FloatField, F
from django.db.models.functions import Substr, StrIndex, Cast, Replace, Length
class YelpCompanyAdmin(admin.ModelAdmin):
list_display = ('title','url','messaged','city','annual_revenue','not_available', 'show_annual_revenue1')
def get_queryset(self, request):
replace_strings = ['million', 'milion', 'up to', '$', 'less than', 'False']
qs = YelpCompany.objects.filter(messaged=False,not_available=False)
qs = qs.annotate(
annual_revenue1 = F('annual_revenue')
)
for s in replace_strings:
qs = qs.annotate(
annual_revenue1 = Replace(F('annual_revenue1'), Value(s), Value(''))
)
qs = qs.annotate(
annual_revenue1 = Case(
When(annual_revenue1=None, then=Value(0.0)),
default=Cast(Trim(F('annual_revenue1')), FloatField())
)
)
return qs.order_by('annual_revenue1')
def show_annual_revenue1(self, inst):
return inst.annual_revenue1
show_annual_revenue1.admin_order_field = 'annual_revenue1'
Это дает гибкость для добавления любых строк, которые могут появиться в списке. Вы можете создать свой список строк замены динамически из исходного набора запросов, если вам нравится:
replace_strings2 = []
for q in qs.values_list('annual_revenue', flat=True):
if not q is None:
s = ''.join([x for x in q if not q.isdigit()])
replace_strings2.extend(s.split())
replace_strings = []
for s in replace_strings2:
try:
float(s)
except ValueError:
replace_strings.append(s)