django — поле запроса order_by, содержащее символы и целые числа

У меня есть модель с полем (назовем его this_field), которое хранится как string. Значения в this_field представлены в форме Char### - например, они имеют такие значения, как: A4 или A34 или A55 (обратите внимание, что они всегда будут иметь один и тот же первый символ).

Есть ли способ выбрать все записи и упорядочить их по этому полю? В настоящее время, когда я делаю .order_by('this_field'), я получаю такой порядок:

A1 A13 A2 A25 и т.д...

Я хочу:

A1 A2 A13 A25 и т.д...

Любые методы или решения наилучшего подхода для правильного упорядочения этого набора запросов?


person Garfonzo    schedule 18.03.2013    source источник


Ответы (3)


Порядок набора запросов обрабатывается серверной частью базы данных, а не Django. Это ограничивает возможности изменения способа упорядочения. Вы можете либо загрузить все данные и отсортировать их с помощью Python, либо добавить в свой запрос дополнительные параметры, чтобы база данных использовала какую-то пользовательскую сортировку, определив функции.

Используйте набор запросов extra( ) позволит вам делать то, что вы хотите, выполняя пользовательский SQL для сортировки, но за счет снижения переносимости.

В вашем примере, вероятно, было бы достаточно разделить поле ввода на два набора данных: начальный символ и оставшееся целочисленное значение. Затем вы можете применить сортировку к обоим столбцам. Вот пример (непроверенный):

qs = MyModel.objects.all()

# Add in a couple of extra SELECT columns, pulling apart this_field into
# this_field_a (the character portion) and this_field_b (the integer portion).

qs = qs.extra(select={
              'this_field_a': "SUBSTR(this_field, 1)",
              'this_field_b': "CAST(substr(this_field, 2) AS UNSIGNED)"})

Вызов extra добавляет два новых поля в вызов SELECT. Первое предложение извлекает первый символ поля, второе предложение преобразует оставшуюся часть поля в целое число.

Теперь должно быть возможно order_by в этих полях. При указании двух полей для order_by порядок сначала применяется к символьному полю, а затем к целочисленному полю.

eg

qs = qs.order_by('this_field_a', 'this_field_b')

Этот пример должен работать как на MySql, так и на SQLite. Также должна быть возможность создать одно дополнительное поле, которое используется только для сортировки, что позволит вам указать только одно поле в вызове order_by().

person Austin Phillips    schedule 18.03.2013
comment
Это сработало отлично. Хотя мне интересно, отредактировали ли вы свой ответ, добавив где-нибудь дополнительную закрытую скобку... Мне пришлось добавить ее. Тем не менее, работал как шарм! Спасибо :) - person Garfonzo; 18.03.2013

Если вы часто используете этот порядок сортировки и в больших таблицах, вам следует подумать о двух отдельных полях, содержащих разделенные значения:

  1. альфа-значения должны быть только в нижнем регистре, в текстовом или символьном поле с установленным db_index=True
  2. числовые значения должны быть в целочисленном поле с установленным на них db_index=True.

qs.order_by('alpha_sort_field', 'numeric_sort_field')

В противном случае вы, вероятно, испытаете некоторое (или даже огромное) влияние на производительность.

person Risadinha    schedule 18.01.2016

Другой способ сделать это — отсортировать QuerySet на основе целочисленной части this_field:

qs = ModelClass.objects.all()
sorted_qs = sorted(qs, key=lambda ModelClass: int(ModelClass.this_field[1:]))
person jurgenreza    schedule 18.03.2013