Django ORM: Выполнение условного `order_by` [дубликат]
Допустим, у человека есть такая простая модель:
from django.db import models
class Foo(models.Model):
n = models.IntegerField()
В SQL вы можете выполнить порядок по с условием например,
select * from foo orber by n=7, n=17, n=3, n
Это отсортирует строки сначала по возрастанию, если n
равно 7, затем если n
равно 14, затем если n
равно 3, и, наконец, по возрастанию n.
Как сделать то же самое с Django ORM? Это не рассматривается в их order_by
документации.
Вы можете использовать .annotate()
для присвоения записям значения custom_order
и использовать затем .order_by()
для упорядочивания набора запросов на основе этого значения.
Например:
Foo.objects \
.annotate(custom_order=Case(
When(n=7, then=Value(0)),
When(n=17, then=Value(1)),
When(n=3, then=Value(2)),
default=Value(3),
output_field=IntegerField()
) \
.order_by('custom_order', 'n')
Вы можете работать с общим решением, которое выглядит следующим образом:
from django.db.models import Case, IntegerField, When, Value
items = [7, 17, 3]
Foo.objects.alias(
n_order=Case(
*[When(n=item, then=Value(i)) for i, item in enumerate(items)],
default=Value(len(items)),
output_field=IntegerField()
)
).order_by('n_order', 'n')
Таким образом, строится условное выражение цепочки [Django-doc], которое используется первым, и если n
не является одним из них, оно вернется к упорядочиванию с n
само.