いつも動画・ブログでお世話になっております。 <br /> DRFで多対多の参照先がさらにForeignKeyのフィールドを読み込む場合<br /> (下記の例だとBlog ←→ sponsor → user, price)にviewsでprefetchを指定してもN+1回読み込まれてしまいます。 <br />
※該当する箇所だけ簡略化して書いています。
# models.py class User(TimeStampedModel): name = models.CharField() class Price(TimeStampedModel): price = models.PositiveIntegerField() ## 記事を応援してくれた人という設定 class Sponsor(TimeStampedModel): user = models.ForeignKey(User) price = models.ForeignKey(Price) class Blog(TimeStampedModel): title = models.CharField() ... sponsor = models.ManyToManyField(Sponsor, blank=True) ## 記事のいいね機能 class Likes(TimeStampedModel): blog = models.ForeignKey(Blog) user = models.ForeignKey(User) # serializer.py class UserSerializer(serializers.ModelSerializer): class Meta: model = User fields = '__all__' class PriceSerializer(serializers.ModelSerializer): class Meta: model = Price fields = '__all__' class SponsorSerializer(serializers.ModelSerializer): user = UserSerializer() price = PriceSerializer() class Meta: model = Sponsor fields = '__all__' class BlogSerializer(serializers.ModelSerializer): sponsor = SponsorSerializer(many=True) likes = serializers.SerializerMethodField() def get_likes(self, obj): likes = LikeData.objects.filter(blog=obj).count() user = self.context['request'].user is_liked = LikeData.objects.filter(user=user, blog=obj).exists() return {'likes': likes, 'is_liked': is_liked} class Meta: model = Blog fields = '__all__' # views.py class BlogViewSet(viewsets.ModelViewSet): queryset = Blog.objects.all() serializer_classes = BlogSerializer
1 . querysetに対してPrefetch
class BlogViewSet(viewsets.ModelViewSet): queryset = Blog.objects.all().prefetch_related(Prefetch('sponsor', Sponsor.objects.select_related('user', 'price')))
としましたが、UserとPriceが何回も重複して呼ばれてしまいました。
2 . django-auto-prefetchingの導入 SerializerMethodFieldがあると自動で認識してくれず、少し複雑になり、エラーが起こったため諦めました
実際のものとは少し変えて書いてあるので、テーブル構造を変えて対応するのではなく、クエリ側での改善を試みたいです。
Prefetchの理解に誤りがあるのでしょうか?
それともこのケースだと生SQLで対応しないと無理なのでしょうか。
知見をいただきたいです!よろしくお願いいたします。