Почему Django prefetch_related приводит к сотням лишних SQL-запросов?

Мои отношения таковы:

  1. Портфель имеет отношение многие 2 многие к LoanTape через PortfolioLoanTapes
  2. .
  3. У котировки есть много LoanTapes
  4. У котировки много документов

Я пытаюсь запросить Portfolio и все связанные с ним документы со звездами в вызове API GET портфеля в DRF ModelViewSet.

models.py

class Portfolio(models.Model):
    loan_tapes = models.ManyToManyField("LoanTape", through="PortfolioLoanTapes")

class PortfolioLoanTapes(models.Model):
    portfolio = models.ForeignKey(Portfolio, on_delete=models.PROTECT)
    loan_tape = models.ForeignKey(LoanTape, on_delete=models.PROTECT)

class LoanTape(models.Model):
    portfolios = models.ManyToManyField("Portfolio", through="PortfolioLoanTapes")
    quote = models.ForeignKey("Quote", on_delete=models.PROTECT, blank=False, null=False, related_name="loan_tapes")

class Quote(models.Model):
    ...

class Document(models.Model):
    quote = models.ForeignKey(Quote, on_delete=models.PROTECT, related_name="documents")
    is_starred = models.BooleanField(default=False)

view.py

    def get_queryset(self):
        starred_documents_qs = Document.objects.filter(is_starred=True)
        quotes_prefetch = Prefetch('quote__documents', queryset=starred_documents_qs, to_attr='starred_documents')
        loan_tapes_prefetch = Prefetch('portfolioloantapes_set__loan_tape', queryset=LoanTape.objects.prefetch_related(quotes_prefetch))
        qs = Portfolio.objects.prefetch_related(loan_tapes_prefetch).filter(deleted__isnull=True)

        return qs

serializer.py

class PortfolioDetailSerializer(serializers.ModelSerializer):
    loan_tapes = PortfolioLoanTapeSerializer(many=True, read_only=True, source="portfolioloantapes_set")


class PortfolioLoanTapeSerializer(serializers.ModelSerializer):
    def to_representation(self, instance):
        ret = super().to_representation(instance)
        ret.update(LoanTapeSerializer(instance.loan_tape).data)
        return ret


class LoanTapeSerializer(serializers.ModelSerializer):
    image_url = serializers.SerializerMethodField()

    def get_image_url(self, instance):
        if starred_docs := getattr(instance.quote, 'starred_documents', []):
            return starred_docs[0].url

test.py (не хватает некоторых объектов настройки)


    def test_retrieve_query_count(self):
        with self.assertNumQueries(4):
            response = self.client.get(f"/api/v1/portfolios/{portfolio.id}/", **self.headers)
            self.assertEqual(response.status_code, 200)

При утверждении количества запросов в тесте выше, Django делает 224 вызова DB!!! Может быть, мои объекты prefetch настроены неправильно? Есть ли более эффективный путь в префетче? Я совсем запутался и не могу понять, почему так много SQL-запросов делается на такой относительно простой вызов.....

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