perf: P1 性能优化批量修复 + kefu 视图拆分

P1 性能优化(避免循环内 N+1 / N 次 DB 查询):
- shop_order_views._batch_images: 移除 ThreadPoolExecutor 掩盖的 N 次查询,改单次批量 + Python 侧分组
- product_query.DashouHuiyuanList: 5N 查询 -> 3 次批量预取 + 本地闭包判断
- roles.GetRolePermissionView / 用户列表: 循环内 RolePermission/Permission/UserRole/Role -> 批量 __in 预取
- guanli / zuzhang 杜次分红 4.2/4.3: 循环内 update_or_create + 单条 delete -> bulk_create + bulk_update + 批量 delete
- admin_config QQ 群配置: 循环内 exists/first/save/create -> 批量预取 + bulk_create + bulk_update
- jituan 服务层多处合并统计查询、批量预取 map
- rank 多处循环 N+1 改批量预取
- backend 多处循环内 count/create 改批量
- config/orders/merchant_ops 多处循环 N+1 改批量预取

其他改动:
- users/views/kefu.py 拆分为 kefu_base/kefu_dashou/kefu_orders/kefu_punishment/kefu_withdraw 5 个文件
- 删除遗留脚本 check_prod_uid.py / create_rbac_tables.sql
This commit is contained in:
2026-07-05 23:17:38 +08:00
parent 76ea5f8255
commit f1c8633345
54 changed files with 5332 additions and 4494 deletions

View File

@@ -1,4 +1,4 @@
import io
import io
import os
import re
import time
@@ -270,6 +270,13 @@ class DashouPaihangView(APIView):
# 第一名数量不足,不展示
return [], False
# 批量预取老板扩展表昵称
_boss_user_ids = [g.user_id for g in guanshi_list]
_boss_nicheng_map = {
b.user_id: b.nickname
for b in UserBoss.query.filter(user_id__in=_boss_user_ids).only('user_id', 'nickname')
}
# 构建返回数据
paihang_list = []
for index, guanshi in enumerate(guanshi_list):
@@ -277,8 +284,7 @@ class DashouPaihangView(APIView):
user_main = guanshi.user
# 管事的昵称需要查询老板扩展表
boss_profile = UserBoss.query.filter(user=user_main).first()
guanshi_nicheng = boss_profile.nickname if boss_profile else '未设置昵称'
guanshi_nicheng = _boss_nicheng_map.get(guanshi.user_id, '未设置昵称')
# 获取头像相对URL
touxiang_url = user_main.Avatar or ''
@@ -337,6 +343,13 @@ class DashouPaihangView(APIView):
# 第一名流水不足,不展示
return [], False
# 批量预取老板扩展表昵称
_boss_user_ids = [s.user_id for s in shangjia_list]
_boss_nicheng_map = {
b.user_id: b.nickname
for b in UserBoss.query.filter(user_id__in=_boss_user_ids).only('user_id', 'nickname')
}
# 构建返回数据
paihang_list = []
for index, shangjia in enumerate(shangjia_list):
@@ -344,8 +357,7 @@ class DashouPaihangView(APIView):
user_main = shangjia.user
# 商家的昵称需要查询老板扩展表
boss_profile = UserBoss.query.filter(user=user_main).first()
shangjia_nicheng = boss_profile.nickname if boss_profile else '未设置昵称'
shangjia_nicheng = _boss_nicheng_map.get(shangjia.user_id, '未设置昵称')
# 获取头像相对URL
touxiang_url = user_main.Avatar or ''
@@ -604,21 +616,21 @@ class GetXiugaiJiluView(APIView):
records = cursor.fetchall()
# 🔥 6. 处理查询结果(严格按照字段类型处理)
# 预查询修改者账号信息(循环外执行一次,避免循环内重复查询同一 SQL
xiugaizhe_zhanghao = ''
with connection.cursor() as cursor2:
cursor2.execute(
"SELECT phone, yonghuid FROM user_main WHERE phone = %s OR yonghuid = %s LIMIT 1",
[xiugaizhe_zhanghaoid, xiugaizhe_zhanghaoid]
)
xiugaizhe_info = cursor2.fetchone()
if xiugaizhe_info:
xiugaizhe_zhanghao = str(xiugaizhe_info[0]) if xiugaizhe_info[0] else str(xiugaizhe_info[1]) if \
xiugaizhe_info[1] else xiugaizhe_zhanghaoid
jilu_list = []
for record in records:
# 获取修改者账号信息(都是字符串)
xiugaizhe_zhanghao = ''
with connection.cursor() as cursor2:
# 🔥 phone和yonghuid都是CharField用字符串查询
cursor2.execute(
"SELECT phone, yonghuid FROM user_main WHERE phone = %s OR yonghuid = %s LIMIT 1",
[xiugaizhe_zhanghaoid, xiugaizhe_zhanghaoid]
)
xiugaizhe_info = cursor2.fetchone()
if xiugaizhe_info:
# 🔥 都是字符串
xiugaizhe_zhanghao = str(xiugaizhe_info[0]) if xiugaizhe_info[0] else str(xiugaizhe_info[1]) if \
xiugaizhe_info[1] else xiugaizhe_zhanghaoid
# 修改者账号信息已预查询,直接使用
# 获取会员名称(如果有)
huiyuan_mingzi = ''