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
192 lines
7.6 KiB
Python
192 lines
7.6 KiB
Python
"""rank.views.biaoqian - auto-generated by split script."""
|
||
import json
|
||
import logging
|
||
from decimal import Decimal
|
||
from django.db import models, transaction
|
||
from django.db.models import F, Prefetch
|
||
from rest_framework.views import APIView
|
||
from rest_framework.response import Response
|
||
from rest_framework.permissions import IsAuthenticated
|
||
from ..utils import get_tag_fee, create_shenhe_jilu, validate_shenheguan
|
||
from ..models import (
|
||
YonghuChenghao, Chenghao, KaoheCishuFeiyong, KaoheJujueJilu,
|
||
KaoheguanBankuai, Bankuai, ShenheJilu, KaoheJiluFeiyong
|
||
)
|
||
from users.models import UserShenheguan, UserDashou
|
||
from users.business_models import User
|
||
from products.models import ShangpinLeixing
|
||
|
||
|
||
|
||
|
||
logger = logging.getLogger(__name__)
|
||
|
||
|
||
class DashouBiaoqianView(APIView):
|
||
"""获取当前打手所有称号标签"""
|
||
permission_classes = [IsAuthenticated]
|
||
|
||
def post(self, request):
|
||
try:
|
||
yonghu = request.user
|
||
# 查询用户的所有称号关联,一次连表取出
|
||
relations = YonghuChenghao.objects.filter(
|
||
yonghu=yonghu
|
||
).select_related('chenghao')
|
||
|
||
chenghao_list = []
|
||
for rel in relations:
|
||
ch = rel.chenghao
|
||
# 解析特效描述 JSON(前端需要对象)
|
||
texiao_json = {}
|
||
if ch.texiao_miaoshu:
|
||
try:
|
||
texiao_json = json.loads(ch.texiao_miaoshu)
|
||
except json.JSONDecodeError:
|
||
texiao_json = {}
|
||
chenghao_list.append({
|
||
'mingcheng': ch.mingcheng,
|
||
'tubiao_url': ch.tubiao_url or '',
|
||
'texiao_json': texiao_json,
|
||
})
|
||
|
||
return Response({
|
||
'code': 0,
|
||
'msg': '成功',
|
||
'data': {'chenghao_list': chenghao_list}
|
||
})
|
||
except Exception as e:
|
||
logger.error(f"获取打手标签失败: {e}", exc_info=True)
|
||
return Response({'code': 1, 'msg': '服务器错误', 'data': None})
|
||
|
||
|
||
class BankuaiBiaoqianView(APIView):
|
||
"""获取商品类型所属板块的所有标签"""
|
||
permission_classes = [IsAuthenticated]
|
||
|
||
def post(self, request):
|
||
leixing_id = request.data.get('leixing_id') or request.data.get('ProductTypeID')
|
||
if not leixing_id:
|
||
return Response({'code': 1, 'msg': '缺少leixing_id'})
|
||
|
||
try:
|
||
leixing = ShangpinLeixing.objects.select_related('bankuai').get(id=leixing_id)
|
||
except ShangpinLeixing.DoesNotExist:
|
||
return Response({'code': 2, 'msg': '商品类型不存在'})
|
||
|
||
bankuai = leixing.bankuai
|
||
if not bankuai:
|
||
return Response({'code': 0, 'data': {'biaoqian_list': []}})
|
||
|
||
# 获取该板块下所有类型的标签(leixing可以为dashou/shangjia等,这里先返回所有)
|
||
chenghao_list = Chenghao.objects.filter(bankuai=bankuai, leixing='dashou')
|
||
data = []
|
||
from jituan.services.club_context import resolve_effective_club_id
|
||
from jituan.services.club_kaohe_chenghao import filter_chenghao_ids_for_pool
|
||
|
||
club_id = resolve_effective_club_id(request, request.user)
|
||
allowed_ids = set(
|
||
filter_chenghao_ids_for_pool(club_id, list(chenghao_list.values_list('id', flat=True)))
|
||
)
|
||
for ch in chenghao_list:
|
||
if ch.id not in allowed_ids:
|
||
continue
|
||
texiao_json = {}
|
||
if ch.texiao_miaoshu:
|
||
try:
|
||
texiao_json = json.loads(ch.texiao_miaoshu)
|
||
except:
|
||
pass
|
||
data.append({
|
||
'id': ch.id,
|
||
'mingcheng': ch.mingcheng,
|
||
'texiao_json': texiao_json
|
||
})
|
||
return Response({'code': 0, 'data': {'biaoqian_list': data}})
|
||
|
||
|
||
class KaoheJinpaiTagsView(APIView):
|
||
"""获取考核金牌页面的标签和板块信息"""
|
||
permission_classes = [IsAuthenticated]
|
||
|
||
def post(self, request):
|
||
try:
|
||
user = request.user
|
||
# 获取用户已拥有的标签名称集合
|
||
owned_names = set(
|
||
YonghuChenghao.objects.filter(yonghu=user, chenghao__leixing='dashou')
|
||
.values_list('chenghao__mingcheng', flat=True)
|
||
)
|
||
|
||
# 板块列表(prefetch 一次性加载标签和费用,避免三层嵌套 N+1)
|
||
plate_list = []
|
||
all_bankuai = Bankuai.objects.prefetch_related(
|
||
Prefetch(
|
||
'chenghao_set',
|
||
queryset=Chenghao.objects.filter(leixing='dashou').prefetch_related(
|
||
Prefetch(
|
||
'kaohecishufeiyong_set',
|
||
queryset=KaoheCishuFeiyong.objects.order_by('cishu'),
|
||
)
|
||
),
|
||
to_attr='dashou_tags'
|
||
)
|
||
).all()
|
||
for bk in all_bankuai:
|
||
tag_list = []
|
||
for tag in getattr(bk, 'dashou_tags', []):
|
||
# 费用列表(已预加载,保持 cishu 升序)
|
||
fee_list = [{'cishu': f.cishu, 'feiyong': float(f.feiyong)}
|
||
for f in tag.kaohecishufeiyong_set.all()]
|
||
|
||
# 若没有记录,补充默认费用
|
||
if not fee_list:
|
||
fee_list = [{'cishu': 1, 'feiyong': 5.00}]
|
||
|
||
tag_list.append({
|
||
'id': tag.id,
|
||
'name': tag.mingcheng,
|
||
'texiao_json': json.loads(tag.texiao_miaoshu) if tag.texiao_miaoshu else {},
|
||
'jinpai': tag.kaioi_jinpai,
|
||
'rule': tag.kaohe_guize or '',
|
||
'fee_list': fee_list,
|
||
'owned': tag.mingcheng in owned_names,
|
||
})
|
||
|
||
if tag_list:
|
||
plate_list.append({
|
||
'bankuai_id': bk.bankuai_id,
|
||
'mingcheng': bk.mingcheng,
|
||
'tags': tag_list
|
||
})
|
||
|
||
# 新增:返回所有在职考核官信息(用于指定考核官)
|
||
kaoheguan_list = []
|
||
# select_related 预加载 OneToOne 反向关系 DashouProfile,避免循环内 N+1
|
||
for kg in UserShenheguan.objects.filter(zhuangtai=1).select_related('user', 'user__DashouProfile'):
|
||
uid = kg.user.UserUID
|
||
avatar = kg.user.Avatar or ''
|
||
# 获取考核官的打手昵称(从打手扩展表,已预加载)
|
||
dashou_nick = ''
|
||
dashou_prof = getattr(kg.user, 'DashouProfile', None)
|
||
if dashou_prof:
|
||
dashou_nick = dashou_prof.nicheng or ''
|
||
kaoheguan_list.append({
|
||
'yonghuid': uid,
|
||
'avatar': avatar,
|
||
'dashou_nick': dashou_nick,
|
||
'is_renzheng': kg.is_renzheng,
|
||
'shenhe_zhuangtai': kg.shenhe_zhuangtai,
|
||
})
|
||
|
||
return Response({
|
||
'code': 0,
|
||
'data': {
|
||
'plate_list': plate_list,
|
||
'my_tags': list(owned_names),
|
||
'kaoheguan_list': kaoheguan_list, # 新增
|
||
}
|
||
})
|
||
except Exception as e:
|
||
return Response({'code': 500, 'msg': str(e)}, status=500)
|