Optimization django admin panel queries with select_related and prefetch_related
These are my django models (only the FK s are written)
class SellerBuyable(TimeStampMixin, GBSoftDeleteModel):
seller = models.ForeignKey(Seller,related_name="seller_buyables",on_delete=models.CASCADE, null=True)
buyable = models.ForeignKey(Buyable,on_delete=models.CASCADE,null=True,related_name="seller_buyables",related_query_name='seller_buyable')
...
class CampaignItem(TimeStampMixin, GBSoftDeleteModel):
campaign = models.ForeignKey(Campaign, related_name='items', on_delete=models.CASCADE)
item = models.ForeignKey(SellerBuyable, on_delete=models.CASCADE, null=False)
...
class Campaign(TimeStampMixin, GBSoftDeleteModel):
name = models.CharField()
... (has no FK)
And these are my codes in admin panel:
class CampaignItemStackedInline(SortableStackedInline):
model = CampaignItem
extra = 0
....
@admin.register(Campaign)
class CampaignAdmin(SortableAdminMixin, admin.ModelAdmin):
inlines = [CampaignItemStackedInline]
...
A sample campaign had 11 items. When I open it's page, silk showed 84 queries.
I have simplified them to 40 queries by writing CampaignItemStackedInline like this:
class CampaignItemStackedInline(SortableStackedInline):
model = CampaignItem
extra = 0
def get_queryset(self, request):
qs = super().get_queryset(request)
qs = qs.select_related("campaign", "item__seller", "item__buyable")
return qs
But I still have 3 queries for each "campaign inline item". 1 for Seller table, 1 for buyable and 1 for seller_buyable. I've tried prefetch_related in CampaignAdmin. The last version is this:
@admin.register(Campaign)
class CampaignAdmin(SortableAdminMixin, admin.ModelAdmin):
...
def get_queryset(self, request):
qs = super().get_queryset(request)
qs = qs.prefetch_related(
Prefetch("items", queryset=CampaignItem.objects.select_related("item__seller", "item__buyable"))
)
return qs
But it only adds 1 prefetch query and turns into 41 queries
Hope to send enough info.