© EVILEG 2015-2018
Рекомендует хостинг
TIMEWEB

Django - Урок 033. Передача списка аргументов в метод order_by для сортировки QuerySet

сортировка, sort, Django

Для улучшения удобства использования разделов статей была внедрена сортировка статей по дате, заголовку, и количеству просмотров. Помимо этого была добавлена возможность поиска информации по статьям раздела. Реализуется эта возможность через несколько чекбоксов, которые добавляют названия колонок для сортировки в URL страницы, соответственно страница перезагружается.

Например, в модели данных есть несколько колонок

  • title
  • pub_date
  • views

По ним и будем делать сортировку, которая в обычном варианте запроса выглядела бы так

Article.objects.all().order_by('title', 'pub_date', 'views')

Но поскольку мы используем чекбоксы, то варианты сортировку могу присутствовать, а могу и отсутствовать. Но не будем же мы писать if else блоки на каждую комбинацию чекбоксов? Конечно, нет.

Посмотрим для начала, как может быть написана форма для реализации сортировки. Сразу оговорюсь, что приведу вариант формы без стилизации, которая применена у меня на сайте. Дело в том, что для этого используется Bootstrap 4 Material Design, что несколько усложняем вариант вёрстки и добавит ряд лишних элементов в пример.

<form method="get">
    <button type="submit" class="btn btn-sm btn-primary btn-raised mr-3">{% trans 'Сортировать' %}</button>
    <input name="sort" type="checkbox" value="title" {{ by_title }}>{% trans "по заголовку" %}
    <input name="sort" type="checkbox" value="pub_date" {{ by_date }}>{% trans "по дате" %}
    <input name="sort" type="checkbox" value="views" {{ by_views }}>{% trans "по просмотрам" %}
</form>

Как видите, все чекбоксы в коде имеют имя sort, а значение value будет равно имени колонки, по которой можно будет включить сортировку.

Таким образом в URL будут фигурировать следующие аргументы

?sort=title&sort=pub_date&sort=views

Django позволяет извлечь все аргументы из запроса в качестве списка, который мы можем передать в метод order_by, чтобы выполнить сортировку.

И фактически представление для рендеринга раздела со статьями может выглядеть следующим образом

class SectionView(View):

    def get(self, request, slug):
        section = get_object_or_404(Section, slug=slug)
        sort = request.GET.getlist('sort')
        articles = section.article_set.all().order_by(*sort)

        return render(
            request=request,
            template_name='knowledge/section.html',
            context={
                'section': section,
                'articles': articles
            }
        )

Обратите внимание, на то, что вместо метода get используется метод getlist , который возвращает список значений аргументов, если в запросе фигурировало одно и тоже имя аргумента несколько раз.

sort = request.GET.getlist('sort')

А далее с помощью указателя передаём список в качестве аргументов в метод order_by

articles = section.article_set.all().order_by(*sort)

Для Django рекомендую VDS-сервера хостера Timeweb .

Комментарии

17 мая 2018 г. 3:53
можно же это реализовать через django-filter!
17 мая 2018 г. 6:05

Ну. Массово пока не использую фильтрации, поэтому не искал батареек. Так получилось, что даже не знал про django-filters.

Спасибо. Можете черкануть заметку, как аналог этой статье ;-)
17 мая 2018 г. 15:16

хорошие статьи я много чего нашел тут интересного и нового... мне нравиться!
если вдруг интересно будет по фильтрам вот примерный код)

import django_filters
from .models import Product

CHOICES =[
        ["name", "по алфавиту"],
        ["price", "дешевые сверху"],
        ["-price", "дорогие сверху"]
]


class ProductFilter(django_filters.FilterSet):
    name = django_filters.CharFilter(name='name', lookup_expr='icontains')
    category__slug = django_filters.CharFilter()
    price__gt = django_filters.NumberFilter(name='price', lookup_expr='gt')
    price__lt = django_filters.NumberFilter(name='price', lookup_expr='lt')
    ordering = django_filters.OrderingFilter(choices=CHOICES, required=True, empty_label=None,)

    class Meta:
        model = Product
        exclude = [field.name for field in Product._meta.fields]
        order_by_field = 'name'


from django_filters.views import FilterView
class EnumerationListView(FilterView):
    template_name = '.html'
    model = Lot
    paginate_by = 50
    filterset_class = ProductFilter
    context_object_name = 'product_list'

17 мая 2018 г. 20:23

Спасибо за пример кода.
Когда буду внедрять больше поисковых виджетов на сайт, в первую очередь воспользуюсь вашим примером кода. Благо уже есть некоторые целевые места, где это можно применить.

Комментарии

Только авторизованные пользователи могут оставлять комментарии.
Пожалуйста, Авторизуйтесь или Зарегистрируйтесь
15 июля 2018 г. 20:20
igorpodoba

C++ - Тест 003. Условия и циклы

  • Результат 92баллов,
  • Очки рейтинга8
15 июля 2018 г. 20:17
igorpodoba

C++ - Тест 002. Константы

  • Результат 91баллов,
  • Очки рейтинга8
14 июля 2018 г. 7:47
igorpodoba

C++ - Тест 003. Условия и циклы

  • Результат 71баллов,
  • Очки рейтинга1
Последние комментарии
14 июля 2018 г. 18:49
Евгений Легоцкой

Qt/C++ - Урок 049. QTranslator - динамический перевод мультиязычного приложения на Qt

У меня на руках есть один проект, где какие-то потуги с переводами и подключением этого добра в CMAKE делались.Но там файл перевода добавляется прямо в ресурсы проекта. То есть бинарных qm файл...
14 июля 2018 г. 18:35
Евгений Легоцкой

Django - Урок 036. Как добавить аутентификацию через социальные сети. ВКонтакте

Не, не будет, в данной батарейке уже есть необходимый функционал по разрулированию этой проблемы. Аутентификации из разных социальных сетей будут сливаться на один аккаунт. Так что всё нормаль...
14 июля 2018 г. 4:17
Gerych

Django - Урок 036. Как добавить аутентификацию через социальные сети. ВКонтакте

Мне интересно что будет если в обеих сетях в авторизации одинаковый еmail. Не выведет ли ошибку ?
13 июля 2018 г. 11:55
Arrow

Qt/C++ - Урок 049. QTranslator - динамический перевод мультиязычного приложения на Qt

Хорошая статья. Только один вопрос как это сделать для CMake? Интересует именно запись в CMakeList TRANSLATIONS += QtLanguage_ru.ts CODECFORSRC = UTF-8 П...
Сейчас обсуждают на форуме
14 июля 2018 г. 18:56
Евгений Легоцкой

Как сделать пустое поле в QDateEdit

Слишком много возни, чтобы подробно объяснить, что нужно сделать.... тем более, что у вас ещё зависимость на базу данных... Для начала нужно наследоваться от QCalendarWidget, посколь...
12 июля 2018 г. 15:02
незнаток

Перенос значений таблицы в другую таблицу

void Opisanie::perevod(){ QString mil; int mf = ui->table1->rowCount(); for(int ik = 0; ik < mf; ik++) { QString tu = ui->table1->model()->data(ui...
12 июля 2018 г. 7:46
Евгений Легоцкой

OpenSSL на Windows10

Совсем забыл. Вот в этом посте есть ссылка на скачивание openssl библиотек для msvc-2015
11 июля 2018 г. 16:05
Ruslan Polupan

Наследование от QLineEdit

Из опыта разработки в нашей конторе (для программирование хобби я техподдержка): Если есть возможность переложить логику приложения на базу данных то это лутший вариант. Т.е. использовать по м...

Рекомендуемые страницы