Сортировка Django queryset с помощью пользовательского порядка

Допустим, у меня есть следующая модель Django:

class Todo(models.Model):
    class Priority(models.IntegerChoices):
        HIGH = 1, "High"
        LOW = 2, "Low"
        MEDIUM = 3, "Medium"

    title = models.CharField(max_length=255)
    priority = models.PositiveSmallIntegerField(choices=Priority.choices, db_index=True)

Следующие данные испытаний через фабричного мальчика:

import factory
from factory.django import DjangoModelFactory

class TodoFactory(DjangoModelFactory):
    class Meta:
        model = Todo

    title = factory.Sequence(lambda n: f"Todo {n}")

def test_custom_db_sort():
    todo1 = TodoFactory(priority=Todo.Priority.MEDIUM)
    todo2 = TodoFactory(priority=Todo.Priority.HIGH)
    todo3 = TodoFactory(priority=Todo.Priority.LOW)
    todo4 = TodoFactory(priority=Todo.Priority.MEDIUM)
    todo5 = TodoFactory(priority=Todo.Priority.HIGH)

Я хочу получить объекты Todo из базы данных и отсортировать их по приоритету HIGH -> LOW. К сожалению, Todo.Priority не упорядочен правильно, поэтому я не могу сортировать по нему. Я пришел к следующему решению:

PREFERENCE = {
    Priority.HIGH: 1,
    Priority.MEDIUM: 2,
    Priority.LOW: 3,
}
result = sorted(
    Todo.objects.all(),
    key=lambda x: [PREFERENCE[x.priority], x.id]
)

Это работает, но я бы предпочел сортировку в базе данных по нескольким причинам (например, быстрее, лучше делать работу в БД, а не в Python). Есть ли способ выполнить этот запрос в базе данных?

Использование условного выражения (Case(...), When(...)) выражения

from django.db.models import Case, When, Value

new_priority = Case(
    When(priority=Todo.Priority.HIGH, then=Value(1)),
    When(priority=Todo.Priority.MEDIUM, then=Value(2)),
    When(priority=Todo.Priority.LOW, then=Value(3)),
)

qs = Todo.objects.annotate(new_priority=new_priority).order_by("new_priority")

Если у меня есть выбор, я бы предпочел обновить значения выбора Priority вместо аннотации выражения.

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