私のジャンゴ - パワードアプリが正常に動作しているが、私は、データベースが実際のデータが取り込まれますよう、パフォーマンスの問題に遭遇し始めました。私はDjango Debug Toolbarでいくつかのプロファイリングを行い、多くのエンドポイントがデータを返す過程で数十から数百のクエリを発行することがわかりました。ジャンゴRESTフレームワーク:DRFのAPIを持つネストされたシリアライザのためのプリフェッチの設定
私は以前にデータベースクエリに関しては何も最適化されていなかったので、私は、このことを期待。しかし、私はプリフェッチを設定しているので、適切にプリフェッチされたシリアライザ・データを別のシリアライザにネストすると、そのシリアライザ・データを正しく使用することができません。私はこれをawesome postとして、さまざまなプリフェッチ方法について考える方法のガイドとして使用してきました。私は/api/readinggroups/
エンドポイントを打ったとき
現在、私のReadingGroup
シリアライザが適切にプリフェッチを行います。私の問題は/api/userbookstats/
エンドポイントで、すべてUserBookStats
のオブジェクトを返します。関連するシリアライザUserBookStatsSerializer
は、ネストされたReadingGroupSerializer
を持っています。
モデル、シリアライザ、以下のようにビューセットは、次のとおり
models.py
class ReadingGroup(models.model):
owner = models.ForeignKeyField(settings.AUTH_USER_MODEL)
users = models.ManyToManyField(settings.AUTH_USER_MODEL)
book_type = models.ForeignKeyField(BookType)
....
<other group related fields>
def __str__(self):
return '%s group: %s' % (self.name, self.book_type)
class UserBookStats(models.Model):
reading_group = models.ForeignKey(ReadingGroup)
user = models.ForeignKey(settings.AUTH_USER_MODEL)
alias = models.CharField()
total_books_read = models.IntegerField(default=0)
num_books_owned = models.IntegerField(default=0)
fastest_read_time = models.IntegerField(default=0)
average_read_time = models.IntegerField(default=0)
serializers.py
class ReadingGroupSerializer(serializers.ModelSerializer):
users = UserSerializer(many = True,read_only=True)
owner = UserSerializer(read_only=True)
class Meta:
model = ReadingGroup
fields = ('url', 'id','owner', 'users')
@staticmethod
def setup_eager_loading(queryset):
#select_related for 'to-one' relationships
queryset = queryset.select_related('owner')
#prefetch_related for 'to-many' relationships
queryset = queryset.prefetch_related('users')
return queryset
class UserBookStatsSerializer(serializers.HyperlinkedModelSerializer):
reading_group = ReadingGroupSerializer()
user = UserSerializer()
awards = AwardSerializer(source='award_set', many=True)
class Meta:
model = UserBookStats
fields = ('url', 'id', 'alias', 'total_books_read', 'num_books_owned',
'average_read_time', 'fastest_read_time', 'awards')
@staticmethod
def setup_eager_loading(queryset):
#select_related for 'to-one' relationships
queryset = queryset.select_related('user')
#prefetch_related for 'to-many' relationships
queryset = queryset.prefetch_related('awards_set')
#setup prefetching for nested serializers
groups = Prefetch('reading_group', queryset ReadingGroup.objects.prefetch_related('userbookstats_set'))
queryset = queryset.prefetch_related(groups)
return queryset
views.py
をclass ReadingGroupViewset(views.ModelViewset):
def get_queryset(self):
qs = ReadingGroup.objects.all()
qs = self.get_serializer_class().setup_eager_loading(qs)
return qs
class UserBookStatsViewset(views.ModelViewset):
def get_queryset(self):
qs = UserBookStats.objects.all()
qs = self.get_serializer_class().setup_eager_loading(qs)
return qs
私は(私は実際にそのエンドポイントhereため、重複クエリを排除について投稿)ReadingGroup
エンドポイントのプリフェッチを最適化してきた、そして今、私はUserBookStats
エンドポイントに取り組んでいます。
私が抱えている問題は、現在のsetup_eager_loading
がUserBookStatsSerializer
で、ReadingGroupSerializer
の熱心な読み込み方法で設定されたプリフェッチを使用していないようです。私はまだPrefetch
オブジェクトのシンタックスには少しぼんやりしています - 私はそのアプローチを試してみるとよい答えがthisです。
明らかUserBookStatsViewset
のget_queryset
方法はReadingGroup
のオブジェクトのsetup_eager_loading
を呼び出すことはありませんが、私は同じプリフェッチを達成するための方法があります確信しています。二重のアンダースコアの構文を使用して、内部の関係をプリフェッチ
あなたはエレガントなソリューションか何か解決策について質問していますか? 'queryset = queryset.prefetch_related( 'reading_group'、 'reading_group__users'、 'reading_group__owner')'はうまくいくはずです。 – serg
どのような解決策が素晴らしいだろう - とうわー、それは素晴らしいです。それは完璧に働くので、答えとして提出すれば、私は受け入れます。 Prefetchオブジェクトを置き換えます。これはプリフェッチのデカップルのような洗練されたソリューションに使用したいと考えていたものですが、これは本当にうまく動作します。ありがとう! – dkhaupt