Django When(...) object SQL отсутствует при использовании с __in lookup с пустым списком в качестве значения, что приводит к ProgrammingError

используя Django 3.0 (будет обновлен), я получаю некорректный SQL, который приводит к django.db.utils.ProgrammingError, и мне интересно, может ли кто-нибудь помочь мне понять почему.

Интересно, возникает ли эта проблема и в более новых версиях Django? Но я надеюсь, что смогу заставить его работать без необходимости сразу же обновлять Django.

Запрос модели Я аннотирую поле к каждому экземпляру и использую Case и When с этим, и кажется, что ошибка происходит при использовании отрицаемого объекта Q с поиском __in, который получает пустой список в качестве значения.

Я покажу три примера, которые очень похожи, но приводят к разным SQL. Только первый пример приводит к ошибочному SQL.

Пример запроса, который приводит к некорректному SQL:

Activity.objects.all()
.annotate(
    employee_authorized=Case(
        When(~Q(case__assigned_unit__in=[]), then=Value(False)),
        default=Value(True),
        output_field=BooleanField(),
    )
)

Это приводит к следующему SQL, где нет ничего между WHEN и THEN. В результате получается django.db.utils.ProgrammingError.

SELECT "activity_activity"."id",
       ...
       CASE WHEN THEN False ELSE True END AS "employee_authorized"
FROM "activity_activity"
         LEFT OUTER JOIN "case_case" ON ("activity_activity"."case_id" = "case_case"."id")

Приведенный ниже пример, похоже, приводит к логическому SQL. Единственное отличие заключается в том, что объект Q не отрицается.

Activity.objects.all()
.annotate(
    employee_authorized=Case(
        When(Q(case__assigned_unit__in=[]), then=Value(False)),
        default=Value(True),
        output_field=BooleanField(),
    )
)

SQL:

SELECT "activity_activity"."id",
       ...
       True AS "employee_authorized"
FROM "activity_activity"
         LEFT OUTER JOIN "case_case" ON ("activity_activity"."case_id" = "case_case"."id")

Еще один пример, который действительно приводит к логическому SQL, при этом отрицая объект Q, но используя список, который не является пустым.

Activity.objects.all()
.annotate(
    employee_authorized=Case(
        When(~Q(case__assigned_unit__in=[OrgUnit.objects.first()]), then=Value(False)),then=Value(False)),
        default=Value(True),
        output_field=BooleanField(),
    )
)

Что приводит к следующему SQL:

SELECT "activity_activity"."id",
       ...
       CASE
           WHEN NOT ("case_case"."assigned_unit_id" IN (251) AND "case_case"."assigned_unit_id" IS NOT NULL) THEN False
           ELSE True END AS "employee_authorized"
FROM "activity_activity"
         LEFT OUTER JOIN "case_case" ON ("activity_activity"."case_id" = "case_case"."id")
<

Одна из идей, как избежать этого, - "переключить" условие по умолчанию и использовать Q() вместо ~Q()

.annotate(
    employee_authorized=Case(
        When(Q(case__assigned_unit__in=[]), then=Value(True)),
        default=Value(False),
        output_field=BooleanField(),
    )
)
Вернуться на верх