Сортировка 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
вместо аннотации выражения.