Лексографическое упорядочивание в Django для кортежей с предложением where

В рамках некоторого пользовательского кода пагинации на основе курсора в Python Django, я хотел бы иметь следующую фильтрацию и упорядочивание на общем наборе Queryset (где я не знаю имя таблицы заранее)

WHERE (col_a, col_b) > (%s, %s)
ORDER BY (col_a, col_b)

Как это можно выразить в терминах Django ORM?

Примечание: я бы хотел, чтобы SQL сохранял сравнение кортежей и не основывался на предложениях AND. В некоторых предыдущих тестах казалось более вероятным, что PostgreSQL будет использовать многоколоночные индексы.

Ниже представлен способ, который работает в Django pre 3.2, используя annotate (который также, к сожалению, нуждается в небольшом хаке установки output_field, хотя значение не используется).

from django.db.models import F, Func, TextField

col_a_col_b = Func(F('col_a'), F('col_b'), function='ROW', output_type=TextField())
col_a_col_b_from = Func(col_a_value, col_b_value, function='ROW')

filtered_queryset = queryset
    .annotate(col_a_col_b=col_a_col_b)
    .filter(col_a_col_b__gt=col_a_col_b_from)
    .order_by('col_a', 'col_b')

В Django 3.2+ вы можете использовать alias вместо annotate

Это работает, поскольку то, что называется кортежем, на самом деле является сокращением для Конструктора строк, т.е. (col_a, col_b) это то же самое, что ROW(col_a, col_b)

Вышеизложенное основано на информации в этом билете

Вернуться на верх