Как отсортировать список объектов в шаблоне в алфавитном порядке?

Я хочу отобразить список объектов в общем классе отображения Django ListView. И, чтобы было красивее, стараюсь сортировать по алфавиту. Итак, я использую встроенный тег dictsort для сортировки списка.

Вот краткое изложение кода, который я использовал:

{% for item in object_list|dictsort:"name" %}
  ...
{% empty %}
  ...
{% endfor %}

Проблема в том, что он сортирует имена в соответствии со значениями символов ASCII, а это означает, что большие и малые буквы сортируются по-разному. Вот пример:

Bob
Eve
alice
zoe

И то, что я хотел бы иметь, это следующее:

alice
Bob
Eve
zoe

Я просмотрел документацию и несколько вопросов в SO, но безуспешно. Так что, если у кого-то есть способ добиться этого, я был бы чрезвычайно благодарен.


person perror    schedule 02.02.2014    source источник


Ответы (4)


Вам нужно будет написать собственный фильтр, который сортирует по нижнему регистру. Это довольно просто:

@register.filter
def sort_lower(lst, key_name):
    return sorted(lst, key=lambda item: getattr(item, key_name).lower())

Но если ваш список представляет собой набор объектов из базы данных, вам не следует сортировать их в Python — вы должны заставить базу данных возвращать их в нужном вам порядке.

Изменить

Как вы используете фильтр? Он должен быть точно таким же, как и при диктовке: object_list|sort_lower:"name".

Чтобы отсортировать набор запросов в базе данных, вы можете использовать метод extra, чтобы добавить версию поля в нижнем регистре:

MyModel.objects.all().extra(select={'lower_name': 'LOWER(NAME)'}, order_by='lower_name')
person Daniel Roseman    schedule 02.02.2014
comment
Сначала я попытался определить свой собственный фильтр, как вы упомянули, но мне не удалось заставить его работать в шаблоне. У меня проблема с передачей аргументов в цикле for. И, во-вторых, как заставить БД возвращать отсортированный список из шаблона? - person perror; 02.02.2014
comment
Я получаю ошибку 'MyClass' object has no attribute '__getitem__', я пытаюсь понять, почему. Но я немного застрял. - person perror; 03.02.2014
comment
Извините, я обновил код. Но, как я уже сказал, вы должны использовать версию запроса. - person Daniel Roseman; 03.02.2014
comment
Мне удалось заставить первый метод работать так же, как dictsort. Но я не понимаю, почему добавление дополнительного поля в базу данных лучше, чем его сортировка после запроса. - person perror; 03.02.2014

Я знаю, что это старый вопрос, но самый простой способ сортировки списка без учета регистра:

name_of_list.sort(key=str.lower)

См. ссылку для справки: https://www.afternerd.com/blog/python-sort-list/

Вы можете проверить это, используя этот код:

my_list = ["alice", "Bob", "eve", "Zoe"]
my_list.sort()
print("case sensitive list:")
print(my_list)

my_list.sort(key=str.lower)
print("case insensitive list:")
print(my_list)

Затем, когда вы отображаете свой список в шаблонах, элементы уже будут отсортированы.

person Nikki    schedule 27.06.2019

Очень старый вопрос, но проблема только что возникла для меня. Просто добавьте .lower в dictsort, например:

{% for item in object_list|dictsort:"name.lower" %}

person kdwarn    schedule 18.09.2020

На самом деле я посмотрел исходный код dictsort в .../lib/python2.7/site-packagesdjango/template/defaultfilters.py. И я только что добавил настраиваемый метод cmp:

@register.filter
def sort_lower(value, arg):
    try:
        return sorted(value, key=Variable(arg).resolve,
                      cmp=lambda x,y: cmp(x.lower(), y.lower()))
    except (TypeError, VariableDoesNotExist):
        return ''

Таким образом, можно сортировать по подполям (например, field1.field2), что было необходимо в моем случае.

person perror    schedule 02.02.2014