Как лучше всего сохранить данные предварительной загрузки, чтобы предотвратить N+1 в NestedModelAdmin

У нас есть проблема N+1, заключающаяся в том, что наша NestedModelAdmin должна работать с несколькими базами данных.

После того как мы решили обойти эту проблему, мы решили получить ее заранее в get_queryset. Недостатком является то, что при этом будут получены все записи в этой таблице.

class PODOrderAdmin(nested_admin.NestedModelAdmin):
    list_display = ('order_id', 'get_order_name', 'get_order_type', 'get_suppliers')

    def get_queryset(self, request):
        order_filter = request.GET.get('order')

        qs = super().get_queryset(request).prefetch_related(
            Prefetch(
                'podlineitem_set',
                queryset=PODLineItem.objects.select_related('line_item')
            ),
        ).select_related('order')

        self.suppliers = list(PodSupplier.objects.only('id', 'name'))

        return qs

    def get_suppliers(self, obj):
        # Filter the pod_line_items by pod_order.id to match obj.id
        supplier_ids = [line_item.supplier_id for line_item in obj.podlineitem_set.all()]
        filtered_suppliers = []
        if hasattr(self, 'suppliers'):
            filtered_suppliers = [supplier for supplier in self.suppliers if supplier.id in supplier_ids]
        else:
            filtered_suppliers = PodSupplier.objects.filter(id__in=supplier_ids)
        if filtered_suppliers:
            supplier_names = [(supplier.name,) for supplier in filtered_suppliers]
            return format_html_join('\n', '{}<br>', supplier_names) 
        return None

    get_suppliers.short_description = 'Suppliers'
admin.site.register(PODOrder, PODOrderAdmin)

Мы пытались использовать queryset super().get_queryset(request) для уменьшения количества записей, но это не работает, после проверки некоторых документов выяснилось, что get_queryset вызывается ДО того, как произойдет пагинация

        qs = super().get_queryset(request).prefetch_related('podlineitem_set').select_related('order')

        pod_order_ids = qs.values_list('id', flat=True)
        self.pod_line_items = list(PODLineItem.objects.filter(pod_order_id__in=pod_order_ids))
        self.suppliers = list(PodSupplier.objects.filter(id__in=[pod_line_item.supplier_id for pod_line_item in self.pod_line_items]))

Другим решением является имитация пагинации, но это только усложнит код

    page = int(request.GET.get('p', 0))
    limit = self.list_per_page
    subqueryset = queryset[page * limit: (page + 1) * limit]

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