Как добавить упорядочивание к условиям Case, When в django

Имеется два поля: start_date и end_date. (DateField).

Стандартный для сортировки.

  1. Both start_date and end_date are empty values. (start_date = Null, end_date = Null)
  2. Start_date Most recently and end_date is empty values (start_date = not null, end_date = Null)
  3. If both start_date and end_date have values, end_date most recently (start_date = not Null, end_date = not Null)
  4. If both start_date and end_date have values, start_date most recently (start_date = not Null, end_date = not Null)

Ex) Я хочу

  start       end
1. null       null
2. null       null
3. 2021-10-01 null
4. 2021-09-01 null
5. 2021-09-15 21-09-20
6. 2021-09-01 2021-09-20
7. 2021-09-01 2021-09-15

Я пытался

Model.objects.annotate(
    order1=Case(
        When(Q(start_date__isnull=True) & Q(end_date__isnull=True), then=0),
        When(Q(start_date__isnull=False) & Q(end_date__isnull=True), then=1), # how to order by start_date ??
        When(Q(start_date__isnull=False) & Q(end_date__isnull=False), then=2), # how to order by end_date ??
        output_field=IntegerField()
        ),
    ).order_by('order1')

результат

  start       end
1. null       null
2. null       null
3. 2021-09-01 null # change 3, 4
4. 2021-10-01 null
5. 2021-09-15 21-09-20
6. 2021-09-01 2021-09-20
7. 2021-09-01 2021-09-15

Как я могу решить сложную задачу order by в django?

Я нашел способ работы, хотя скорость медленная. Он не был полностью проверен.

Model.objects.annotate(
    order1=Case(When(Q(start_date__isnull=True) & Q(end_date__isnull=True), then=1), default=0, output_field=IntegerField())
    ).annotate(
        order2=Case(When(Q(start_date__isnull=False) & Q(end_date__isnull=True), then=Max('start_date')), output_field=DateField())
    ).annotate(
        order3=Case(When(Q(start_date__isnull=False) & Q(end_date__isnull=False), then=Max('end_date')), output_field=DateField())
    ).order_by(
        F('order1').desc(nulls_last=True), F('order2').desc(), F('order3').desc(), '-start_date'
    )

Я не думаю, что это идеальное решение, но я делюсь им, потому что оно может кому-то помочь.

Если есть лучший способ, пожалуйста, поделитесь им.

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