[英]How to optimize django-rest-framework serializers with multiple queryset at SerializerMethodField()
I am new to django-rest-framework, and I have a project where I have to optimize the response time of an existing API endpoint.我是 django-rest-framework 的新手,我有一个项目,我必须优化现有 API 端点的响应时间。 Using django-debug-toolbar, found some ways to use prefetch_related() to lessen the SQL queries.使用 django-debug-toolbar,找到了一些使用 prefetch_related() 来减少 SQL 查询的方法。 The problem is I found that the design of the serializer is to have multiple SerializerMethodField to get its statistics values and using prefetch_related only works on all() but on the second serializer method field with filter() is still being queried for every Class loop.问题是我发现序列化器的设计是有多个 SerializerMethodField 来获取它的统计值,并且使用 prefetch_related 仅适用于 all() 但在第二个序列化器方法字段上仍然会为每个 Class 循环查询 filter() 。 You may see sample code below(this is not the specific code but something like this).您可能会在下面看到示例代码(这不是特定代码,而是类似的代码)。
serializer.py:序列化程序.py:
class ClassStatisticsSerializer(ModelBaseSerializer):
total_sessions = serializers.SerializerMethodField()
activity_count = serializers.SerializerMethodField()
def get_total_sessions(self, instance):
sessions = instance.classactivity_set.all()
date = self.context.get('date')
if date:
sessions = sessions.filter(date=date)
if len(sessions) == 0:
return None
return sessions.count()
def get_activity_count(self, instance):
activities = instance.classactivity_set.filter(is_present=False)
date = self.context.get('date')
if date:
activities = activities.filter(date=date)
if len(activities) == 0:
return None
return activities.count()
class Meta:
model = Class
fields = (
'id',
'batch',
'type,
'total_sessions'
'activity_count'
)
views.py:视图.py:
class ClassStatisticsList(APIView):
def get(self, request, *args, **kwargs):
queryset = Class.objects.all().prefetch_related('classactivity_set')
serializer = ClassStatisticsSerializer()
return Response(serializer, status=status.HTTP_200_OK)
In here, when I check the SQL queries on the django debug toolbar, get_total_sessions was being queried once on the SQL but get_activity_count was not since this is another query request on the SQL and being queried for every Class loop. In here, when I check the SQL queries on the django debug toolbar, get_total_sessions was being queried once on the SQL but get_activity_count was not since this is another query request on the SQL and being queried for every Class loop. For now, making a new model is out of the question so i am stuck on how to properly prefetch the second query request.目前,制作一个新的 model 是不可能的,所以我被困在如何正确预取第二个查询请求上。 Hope you can suggest possible way to resolve this.希望您能提出解决此问题的可能方法。 Thank you in advance guys.提前谢谢你们。
You can annotate the count for the objects with queryset and then pass it through serializer class initialization.您可以使用查询集注释对象的计数,然后将其传递给序列化程序 class 初始化。 Like this:像这样:
from django.db.models import Count, Q
condition = {}
if date:
condition = {'date':date}
queryset = Class.objects.all().annotate(
total_sessions=Count(
'classactivity',
filter=Q(**condition),
distinct=True
),
activity_count=Count(
'classactivity',
filter=Q(**condition)&Q(classactivity__is_present=False),
distinct=True
)
)
Then you need to remove SerializerMethodField
s from your serializer, a simple IntegerField should be suffice to get the data from queryset without addional db hits:然后你需要从你的序列化程序中删除SerializerMethodField
s,一个简单的 IntegerField 应该足以从查询集中获取数据而无需额外的数据库命中:
class ClassStatisticsSerializer(ModelBaseSerializer):
total_sessions = serializers.IntegerField()
activity_count = serializers.IntegerField()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.