0

我正在使用 Django Rest Frameworks 编写一个 api。该 api 获取客户列表。客户有许多项目。我的 api 应该返回包含已完成、待处理和总计项目数量的客户列表。我的 api 工作,但它有太多的 sql 查询。api是分页的

class ClientViewSet(ModelViewSet):
    """
     A simple view for creating clients, updating and retrieving
    """
    model = Client
    queryset = Client.objects.all()
    serializer_class = ClientSerializer

现在我的客户序列化器


class ClientSerializer(serializers.ModelSerializer):
    total_projects_count = serializers.SerializerMethodField()
    on_going_projects_count = serializers.SerializerMethodField()
    completed_projects_count = serializers.SerializerMethodField()

    class Meta:
        model = Client
        fields  = __all__

    def get_total_projects_count(self, obj):
        return obj.total_projects_count()

    def get_on_going_projects_count(self, obj):
        return obj.on_going_project_count()

    def get_completed_projects_count(self, obj):
        return obj.completed_projects_count()

项目有一个客户端外键。我尝试使用注释来获取如下所有产品并进行分组。但是注释只在一个领域起作用。

projects = Project.objects.filter(client__in=queryset).values('client', 'status')

如何对多个字段进行分组并将该额外参数传递给序列化程序。或者有没有更好的方法。我也尝试了 prefetch_related 但 total_projects_count 仍在执行新的 sql 查询

4

2 回答 2

0

您需要注释查询集中的计算字段,然后使用注释列返回相关结果,而不是调用方法。这将确保使用单个查询检索所有数据,这肯定会更快。

  1. 更新您的查询集。
class ClientViewSet(ModelViewSet):
    """
     A simple view for creating clients, updating and retrieving
    """
    model = Client
    queryset = Client.objects.annotate(total_projects_count_val=...)
    serializer_class = ClientSerializer
  1. 然后,在您的序列化程序中,使用带注释的列
class ClientSerializer(serializers.ModelSerializer):
    total_projects_count = serializers.SerializerMethodField()
    on_going_projects_count = serializers.SerializerMethodField()
    completed_projects_count = serializers.SerializerMethodField()

    class Meta:
        model = Client
        fields  = __all__

    def get_total_projects_count(self, obj):
        return obj.total_projects_count_val

    ...

查看方法名称,我认为您将需要Case-When注释。

于 2021-02-25T20:13:53.977 回答
0

我使用以下查询减少了查询

from django.db.models import Count, Q

pending = Count('project', filter=Q(project__status="pending"))
finished = Count('project', filter=Q(project__status="finished"))
queryset = Client.objects.annotate(pending=pending).annotate(finished=finished)

现在能够访问 queryset[0].finished 等。当我使用提供drf的分页时,生成的查询是

SELECT "clients_client"."id",
       "clients_client"."created_at",
       "clients_client"."updated_at",
       "clients_client"."client_name",
       "clients_client"."phone_number",
       "clients_client"."email",
       "clients_client"."address_lane",
       "clients_client"."state",
       "clients_client"."country",
       "clients_client"."zipCode",
       "clients_client"."registration_number",
       "clients_client"."gst",
       COUNT("projects_project"."id") FILTER (WHERE "projects_project"."status" = 'pending') AS "pending",
       COUNT("projects_project"."id") FILTER (WHERE "projects_project"."status" = 'finished') AS "finished"
  FROM "clients_client"
  LEFT OUTER JOIN "projects_project"
    ON ("clients_client"."id" = "projects_project"."client_id")
 GROUP BY "clients_client"."id"
 ORDER BY "clients_client"."id" ASC
 LIMIT 6
于 2021-02-26T05:47:31.517 回答