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))