Django queryset перестает работать после многократного использования и фильтров

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

def test_selection():
    po_numbers = (
        Model1.objects
        .filter(schedule__isnull=True)
        .filter(order_hold_type__isnull=True)
        .filter(so_line_status='Awaiting Supply')
        .values_list("customer_po", flat=True)
        .distinct()
    )
    rows = Model1.objects.filter(customer_po__in=po_numbers).annotate(
            total_qty=Sum(F('line_item_quantity')*F('cup_count'))
        ).all()
    
    old_sizes = Sizes.get_old_sizes()
    old_po = rows.filter(
        item_size__in=old_sizes).values_list('customer_po', flat=True).distinct()
    rows = rows.filter(~Q(customer_po__in=old_po)).all()

    partially_scheduled = rows.filter(
        customer_po__in=list(rows.filter(schedule__isnull=False).values_list(
            'customer_po', flat=True).distinct())
    ).all()

    unscheduled = rows.filter(
        ~Q(customer_po__in=list(partially_scheduled.values_list(
            'customer_po', flat=True).distinct().all()))
    ).all()

    model2_po = Model2.objects.values_list('customer_po', flat=True).distinct()
    g1 = unscheduled.exclude(customer_po__in=model2_po)
    po_list = g1.values_list('customer_po', flat=True).distinct()
    print(rows.count(), po_list)

Я подумал, что проблема в моем потоке, поэтому я создал отдельную функцию, чтобы проверить это, и это точка, после которой проблема начинает возникать. Это не приводит к ошибкам, а только к пустоте, и я пытался найти кого-нибудь с подобной проблемой, но ничего не смог найти. До сих пор я пробовал следующие вещи:

  • Используйте filter(~Q()) вместо exclude для фильтрации данных
  • .
  • Использование all() для создания копии набора queryset вместо работы со старым набором
  • Сделать все элементы для фильтрации в виде списка вместо прямого использования наборов квертирования

Но я все еще не могу понять, что здесь может происходить не так. В последних 3 строках кода я получаю g1.count() как 546 строк данных, но список PO оказывается пустым. Но если я использую unscheduled напрямую И удаляю строку g1, то в списке появляется 43 значения.

    g1 = unscheduled.exclude(customer_po__in=model2_po)
    po_list = unscheduled.exclude(customer_po__in=model2_po).values_list('customer_po', flat=True).distinct()

Это дает g1.count() = 546, po_list = empty.

    # g1 = unscheduled.exclude(customer_po__in=model2_po) #commented code
    po_list = unscheduled.exclude(customer_po__in=model2_po).values_list('customer_po', flat=True).distinct()

Это дает po_list = queryset из 43 элементов list.

Избегайте ненужного вызова .all().

Оптимизация и проверка промежуточных результатов.

Будьте осторожны с преобразованиями списков из кверисетов "list(rows.filter(...).values_list(...)) может быть проблематичным, если rows содержит большое количество записей, поскольку преобразование кверисета в список оценивает его немедленно. Лучше использовать цепочку кверисетов напрямую, где это возможно."

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

Вот модифицированная версия вашего кода с улучшениями и шагами по отладке:

def test_selection():

po_numbers = (
    Model1.objects
    .filter(schedule__isnull=True, order_hold_type__isnull=True, so_line_status='Awaiting Supply')
    .values_list("customer_po", flat=True)
    .distinct()
)
rows = Model1.objects.filter(customer_po__in=po_numbers).annotate(
    total_qty=Sum(F('line_item_quantity') * F('cup_count'))
)

old_sizes = Sizes.get_old_sizes()
old_po = rows.filter(item_size__in=old_sizes).values_list('customer_po', flat=True).distinct()
rows = rows.exclude(customer_po__in=old_po)

partially_scheduled = rows.filter(schedule__isnull=False).values_list('customer_po', flat=True).distinct()
unscheduled = rows.exclude(customer_po__in=partially_scheduled)

model2_po = Model2.objects.values_list('customer_po', flat=True).distinct()
g1 = unscheduled.exclude(customer_po__in=model2_po)

po_list = g1.values_list('customer_po', flat=True).distinct()

print(rows.count(), len(po_list))
Вернуться на верх