Предварительная выборка с небольшим количеством фильтров

Имеется таблица Order, которая связана с таблицей Signal через FK. Я перебираю записи из таблицы Signal и обращаюсь к дочерним элементам из таблицы Order. В результате получаю N+1 query. Пробовал делать prefetch_related, Prefetch, но ничего не помогает.

for signal in profile.signals.prefetch_related('orders').all():
    filter1 = signal.orders.filter(position_direction=OrderDirectionChoice.ENTER).order_by("exchanged_at")
    filter2 = signal.orders.filter(position_direction=OrderDirectionChoice.ENTER)
    filter3 = signal.orders.filter(position_direction=OrderDirectionChoice.EXIT)
    filter4 = signal.orders.filter(exchanged_at__isnull=False).first()
    print(filter1, filter2, filter3, filter4)

models.py

class Signal(models.Model):
    ...


class Order(models.Model):
    signal = models.ForeignKey(Signal, related_name="orders", ...)
    position_direction = models.CharField(...)
    exchanged_at = models.BooleanField(...)

Если вы хотите получить список ордеров, основанных на профильных сигналах:

signals_ids = profile.signals.values_list('id',flat=True)
profile_orders = Order.objects.filter(id__in=signals_ids)

Затем вы применяете другие фильтры к переменной profile_orders

profile_orders = profile_orders.filter(...)

Вы можете использовать Prefetch объекты для добавления дополнительных атрибутов к возвращаемым экземплярам, содержащим пользовательские префетчированные наборы запросов, передавая аргумент to_attr

for signal in profile.signals.prefetch_related(
    Prefetch('orders', queryset=Order.objects.filter(position_direction=OrderDirectionChoice.ENTER).order_by("exchanged_at"), to_attr='filter1'),
    Prefetch('orders', queryset=Order.objects.filter(position_direction=OrderDirectionChoice.ENTER), to_attr='filter2'),
    Prefetch('orders', queryset=Order.objects.filter(position_direction=OrderDirectionChoice.EXIT), to_attr='filter3'),
    Prefetch('orders', queryset=Order.objects.filter(exchanged_at__isnull=False), to_attr='filter4'),
).all():
    filter1 = signal.filter1
    filter2 = signal.filter2
    filter3 = signal.filter3
    filter4 = signal.filter4
    print(filter1, filter2, filter3, filter4)

Мне кажется, в вашем алгоритме есть логическая ошибка. Например: filter1, filter2, filter3 - это наборы запросов, а filter4 - объект. Но вы все равно можете создать Prefetch: https://docs.djangoproject.com/en/4.0/ref/models/querysets/#django.db.models.Prefetch

for signal in profile.signals.prefetch_related(
  Prefetch('filter1', queryset=Order.objects.filter(position_direction=OrderDirectionChoice.ENTER).order_by("exchanged_at")),
  Prefetch('filter2', queryset=Order.objects.filter(position_direction=OrderDirectionChoice.ENTER)),
  Prefetch('filte3', queryset= Order.objects.filter(position_direction=OrderDirectionChoice.EXIT)),
  Prefetch('filter4',queryset= Order.objects.filter(exchanged_at__isnull=False)[:1])).all():
    print(signal.filter1.all(), signal.filter2.all(), signal.filter3.all(), signal.filter4.all())
Вернуться на верх