繁体   English   中英

如何在 SerializerMethodField() 使用多个查询集优化 django-rest-framework 序列化程序

[英]How to optimize django-rest-framework serializers with multiple queryset at SerializerMethodField()

我是 django-rest-framework 的新手,我有一个项目,我必须优化现有 API 端点的响应时间。 使用 django-debug-toolbar,找到了一些使用 prefetch_related() 来减少 SQL 查询的方法。 问题是我发现序列化器的设计是有多个 SerializerMethodField 来获取它的统计值,并且使用 prefetch_related 仅适用于 all() 但在第二个序列化器方法字段上仍然会为每个 Class 循环查询 filter() 。 您可能会在下面看到示例代码(这不是特定代码,而是类似的代码)。

序列化程序.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'
        )

视图.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. 目前,制作一个新的 model 是不可能的,所以我被困在如何正确预取第二个查询请求上。 希望您能提出解决此问题的可能方法。 提前谢谢你们。

您可以使用查询集注释对象的计数,然后将其传递给序列化程序 class 初始化。 像这样:

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
    )
)

然后你需要从你的序列化程序中删除SerializerMethodField s,一个简单的 IntegerField 应该足以从查询集中获取数据而无需额外的数据库命中:

class ClassStatisticsSerializer(ModelBaseSerializer):
    total_sessions = serializers.IntegerField()
    activity_count = serializers.IntegerField()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM