Django ORM - .exclude Q vs exclude(ids_in=ids) с Subquery, annotate

Django Queryset exclude() не работает, как ожидалось, с выражениями Q

Я пытаюсь исключить некоторые Project объекты из моего набора запросов, используя два разных метода: один основан на идентификаторах, а другой - на Q выражении для аннотированных данных. Однако каждый из этих методов дает разные результаты, и я не могу понять, почему. Версия с выражением Q возвращает пустой кверисет, хотя это не должно быть так.

Вот соответствующий код:

def check_exclusion():
    # Subquery to get the latest active ReportCalculation message for each project
    latest_calc_message = ReportCalculation.objects.filter(
        project=OuterRef('pk'), 
        is_active=True
    ).order_by('-id').values('message')[:1]

    # Annotate projects with the latest calculation message
    projects_with_messages = Project.objects.annotate(
        latest_message=Subquery(latest_calc_message)
    ).filter(
        end_date__lt=date.today(),  # Project must have ended
        is_active=True  # Project must be active
    ).distinct()

    # Exclude based on latest_message
    excluded_projects = projects_with_messages.filter(
        Q(latest_message__in=("Scheduled.", "Finished successfully.", "Processing ..."))
        | Q(latest_message__startswith="Error")
    ).distinct()
    
    ids = excluded_projects.values_list("id", flat=True)

    # Exclude using Q expression directly on the annotated field
    remaining_projects = projects_with_messages.exclude(
        Q(latest_message__in=("Scheduled.", "Finished successfully.", "Processing ..."))
        | Q(latest_message__startswith="Error")
    ).values('id', 'latest_message')  # Get IDs and messages for verification
    
    print(projects_with_messages.exclude(id__in=ids))  # First method using IDs
    print(remaining_projects.values_list("id", flat=True))  # Second method using Q expression

    return list(excluded_projects), list(remaining_projects)

Что я наблюдаю:

  1. При исключении проектов по идентификаторам (т.е. exclude(id__in=ids)) исключение работает, как и ожидалось.
  2. При использовании выражения Q непосредственно на latest_message (exclude(Q(...))) получается пустой набор запросов, чего не должно быть.

То, что я ожидал:

Оба метода исключения должны возвращать одинаковые результаты или, по крайней мере, похожие. Но сейчас второй подход, использующий выражение Q, ничего не возвращает, и я не могу понять, почему.

Кто-нибудь знает, почему выражение Q ведет себя таким образом? Может быть, что-то не так с тем, как я аннотирую или фильтрую данные?

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