Django 4.x - Условный порядок_бытия набора запросов

Цель

Задача состоит в том, чтобы условно упорядочить QuerySet по одному из трех различных полей даты в представлении на основе другого поля в модели. Поскольку условное упорядочивание не может быть выполнено с помощью Class Meta, я изучаю возможность выполнения этой задачи в представлении.

Вот соответствующий отрывок из models.py:

READING_PROGRESS = [
    ('---', '---'),
    ('1) On Reading List', '1) On Reading List'),
    ('2) Reading In Progress', '2) Reading In Progress'),
    ('3) Completed Reading', '3) Completed Reading'),
]

class ReadingProgress(models.Model):
    record = models.ForeignKey(
        LibraryRecord,
        related_name='record_in_reading_progress',
        on_delete=models.CASCADE,
        null=True,
        blank=True,
        verbose_name='Library record'
    )
    user = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        null=True,
        blank=True
    )
    reading_progress = models.CharField(
        max_length=30,
        choices=READING_PROGRESS,
        default='---'
    )
    date_added = models.DateField(
        auto_now=False,
        auto_now_add=False,
        null=True,
        blank=True,
    )
    date_started = models.DateField(
        auto_now=False,
        auto_now_add=False,
        null=True,
        blank=True,
    )
    date_completed = models.DateField(
        auto_now=False,
        auto_now_add=False,
        null=True,
        blank=True,
    )

    class Meta:
        ordering = [
            'reading_progress',
        ]
        verbose_name_plural = 'Reading Progress'

        unique_together = ('record', 'user',)

    # Record metadata
    date_created = models.DateTimeField(
        auto_now_add=True
    )

    def __str__(self):
        return f'{self.record.title} - {self.reading_progress}'

Соответствующими полями в модели являются:

  • reading_progress
  • date_added
  • date_started
  • date_completed

Каждое поле даты соответствует значению статуса. Я хочу иметь возможность упорядочить набор QuerySet в представлении по полю reading_progress:

  • Когда reading_progress == '1) В списке для чтения', тогда упорядочить по date_added
  • Когда reading_progress == '2) В процессе чтения', то порядок по date_started
  • Когда reading_progress == '3) Законченное чтение', тогда порядок по date_completed

Исследование перед ответом

Я провел некоторое исследование и нашел полезный на вид API QuerySet под названием annotate(). Похоже, это то, что нужно (Django docs).

В документации Django, кажется, говорится, что:

  • я мог бы фильтровать
  • и затем аннотировать отфильтрованный QuerySet
  • .
  • После дополнительных исследований я пришел к выводу, что могу использовать F() как способ реализации запроса в API annotate()

Ответ

Оказывается, при использовании Case нужно обязательно следовать документации и импортировать то, что необходимо. Спасибо поставщику ответа, отмеченного как правильный! :)

Кроме того, я удалил output_field, поскольку существует только один возможный тип данных поля (DateTime) и на него не нужно явно ссылаться.

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

        reading_progress = ReadingProgress.objects.filter(user__username=self.request.user)\
            .annotate(
            date_to_display=Case(
                When(reading_progress='1) On Reading List', then=F('date_added')),
                When(reading_progress='2) Reading In Progress', then=F('date_started')),
                When(reading_progress='3) Completed Reading', then=F('date_completed')),
            )
        )

Вы должны импортировать соответствующие части в пределах views.py

from django.db.models import Case, F, Q, Value, When
Вернуться на верх