From 5881c32c3879d78bc12684d505fb1e6228fde2a0 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 16 Jul 2026 14:41:46 +0800 Subject: [PATCH] =?UTF-8?q?perf:mlog/handover/mlogb=E5=88=97=E8=A1=A8?= =?UTF-8?q?=E6=B6=88=E9=99=A4N+1,select=5Frelated=E7=B2=BE=E7=AE=80?= =?UTF-8?q?=E6=94=B9prefetch,=E4=BF=AEHandover.handoverb=E5=B1=9E=E6=80=A7?= =?UTF-8?q?=E7=BB=95=E8=BF=87prefetch=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 (1M context) --- apps/wpm/models.py | 3 ++- apps/wpm/views.py | 46 +++++++++++++++++++++------------------------- 2 files changed, 23 insertions(+), 26 deletions(-) diff --git a/apps/wpm/models.py b/apps/wpm/models.py index 062b2aee..5b73a7c6 100644 --- a/apps/wpm/models.py +++ b/apps/wpm/models.py @@ -721,7 +721,8 @@ class Handover(CommonADModel): @property def handoverb(self): - return Handoverb.objects.filter(handover=self) + # 用反向关联管理器, 以命中 list 接口的 Prefetch("b_handover") 缓存, 避免 N+1 + return self.b_handover.all() class Handoverb(BaseModel): """TN: 子级交接记录 diff --git a/apps/wpm/views.py b/apps/wpm/views.py index 00627f67..e49583c4 100644 --- a/apps/wpm/views.py +++ b/apps/wpm/views.py @@ -285,6 +285,7 @@ class MlogViewSet(CustomModelViewSet): "handle_user", "equipment", "mgroup", + "mgroup__belong_dept", "material_in", "material_out", "material_in__process", @@ -298,7 +299,22 @@ class MlogViewSet(CustomModelViewSet): # 'equipment_2', 'material_in', 'material_out', 'route__routepack', 'submit_user', # 'supplier', 'ticket', 'mgroup__process', 'test_user', 'handle_leader', 'test_user', 'team', # 'material_in__process', 'material_out__process', "shift", "route"] - prefetch_related_fields = ["handle_users", "material_outs", "equipments"] + prefetch_related_fields = [ + "handle_users", + "material_outs", + "equipments", + # 以下为可选的一对一/外键, 用 prefetch(每个关系仅 1 条 IN 查询)避免 N+1 + # 又不加宽主查询的 JOIN + "team", + "supplier", + "mtask", + "shift", + "test_user", + "handle_user_2", + "handle_leader", + "equipment_2", + "ticket__state", + ] filterset_class = MlogFilter search_fields = [ "material_in__name", @@ -342,27 +358,7 @@ class MlogViewSet(CustomModelViewSet): ] ) def list(self, request, *args, **kwargs): - from django.db import connection - from django.conf import settings - - # 清空之前的查询记录 - connection.queries_log.clear() - - # 调用父类的 list 方法 - response = super().list(request, *args, **kwargs) - - # 获取执行的 SQL 查询 - queries = connection.queries - sql_queries = [] - - for query in queries: - sql_queries.append({"sql": query["sql"], "time": query["time"], "params": query.get("params", [])}) - - # 将 SQL 信息添加到响应中(仅在调试模式) - if settings.DEBUG: - response.data["_debug"] = {"sql_queries": sql_queries, "total_queries": len(queries), "total_time": sum(float(q["time"]) for q in queries)} - - return response + return super().list(request, *args, **kwargs) def add_info_for_list(self, data): czx_dict = {} @@ -590,10 +586,10 @@ class HandoverViewSet(CustomModelViewSet): queryset = Handover.objects.all() list_serializer_class = HandoverListSerializer serializer_class = HandoverSerializer - select_related_fields = ["send_user", "send_mgroup", "send_dept", "recive_user", "recive_mgroup", "recive_dept", "wm", "material_changed", "material"] + select_related_fields = ["send_user", "send_mgroup", "send_dept", "recive_user", "recive_mgroup", "recive_dept", "wm", "material_changed", "material", "material__process"] filterset_class = HandoverFilter search_fields = ["material__name", "material__number", "material__specification", "batch", "material__model", "b_handover__batch", "new_batch", "wm__batch"] - prefetch_related_fields = [Prefetch("b_handover", queryset=Handoverb.objects.select_related("wm__defect"))] + prefetch_related_fields = [Prefetch("b_handover", queryset=Handoverb.objects.select_related("wm__defect")), "ticket__state"] def perform_destroy(self, instance: Handover): user = self.request.user @@ -782,7 +778,7 @@ class MlogbViewSet(CustomListModelMixin, CustomGenericViewSet): perms_map = {"get": "*"} queryset = Mlogb.objects.all() serializer_class = MlogbDetailSerializer - select_related_fields = ["material_out", "material_in", "test_user", "wm_in__defect"] + select_related_fields = ["material_out", "material_out__process", "material_in", "material_in__process", "test_user", "wm_in__defect"] prefetch_related_fields = [ Prefetch("mlogbdefect_set", queryset=MlogbDefect.objects.select_related("defect")), ]